xref: /openbmc/bmcweb/redfish-core/lib/chassis.hpp (revision 28ee563e)
1e37f8451SRapkiewicz, Pawel /*
2e37f8451SRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation
3e37f8451SRapkiewicz, Pawel //
4e37f8451SRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License");
5e37f8451SRapkiewicz, Pawel // you may not use this file except in compliance with the License.
6e37f8451SRapkiewicz, Pawel // You may obtain a copy of the License at
7e37f8451SRapkiewicz, Pawel //
8e37f8451SRapkiewicz, Pawel //      http://www.apache.org/licenses/LICENSE-2.0
9e37f8451SRapkiewicz, Pawel //
10e37f8451SRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software
11e37f8451SRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS,
12e37f8451SRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e37f8451SRapkiewicz, Pawel // See the License for the specific language governing permissions and
14e37f8451SRapkiewicz, Pawel // limitations under the License.
15e37f8451SRapkiewicz, Pawel */
16e37f8451SRapkiewicz, Pawel #pragma once
17e37f8451SRapkiewicz, Pawel 
183ccb3adbSEd Tanous #include "app.hpp"
197a1dbc48SGeorge Liu #include "dbus_utility.hpp"
201c8fba97SJames Feist #include "led.hpp"
213ccb3adbSEd Tanous #include "query.hpp"
227164bc62SChau Ly #include "redfish_util.hpp"
233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
243ccb3adbSEd Tanous #include "utils/collection.hpp"
253ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
26cf7eba09SNan Zhou #include "utils/json_utils.hpp"
271abe55efSEd Tanous 
28e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
29ef4c65b7SEd Tanous #include <boost/url/format.hpp>
301e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
31fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp>
3286d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
331214b7e7SGunnar Mills 
347a1dbc48SGeorge Liu #include <array>
353544d2a7SEd Tanous #include <ranges>
367a1dbc48SGeorge Liu #include <string_view>
377a1dbc48SGeorge Liu 
381abe55efSEd Tanous namespace redfish
391abe55efSEd Tanous {
40e37f8451SRapkiewicz, Pawel 
41e37f8451SRapkiewicz, Pawel /**
425e577bc1SWilly Tu  * @brief Retrieves resources over dbus to link to the chassis
435e577bc1SWilly Tu  *
445e577bc1SWilly Tu  * @param[in] asyncResp  - Shared pointer for completing asynchronous
455e577bc1SWilly Tu  * calls
465e577bc1SWilly Tu  * @param[in] path       - Chassis dbus path to look for the storage.
475e577bc1SWilly Tu  *
485e577bc1SWilly Tu  * Calls the Association endpoints on the path + "/storage" and add the link of
495e577bc1SWilly Tu  * json["Links"]["Storage@odata.count"] =
505e577bc1SWilly Tu  *    {"@odata.id", "/redfish/v1/Storage/" + resourceId}
515e577bc1SWilly Tu  *
525e577bc1SWilly Tu  * @return None.
535e577bc1SWilly Tu  */
getStorageLink(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const sdbusplus::message::object_path & path)545e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
555e577bc1SWilly Tu                            const sdbusplus::message::object_path& path)
565e577bc1SWilly Tu {
575e577bc1SWilly Tu     sdbusplus::asio::getProperty<std::vector<std::string>>(
585e577bc1SWilly Tu         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
595e577bc1SWilly Tu         (path / "storage").str, "xyz.openbmc_project.Association", "endpoints",
60d4b054c1SWilly Tu         [asyncResp](const boost::system::error_code& ec,
615e577bc1SWilly Tu                     const std::vector<std::string>& storageList) {
625e577bc1SWilly Tu         if (ec)
635e577bc1SWilly Tu         {
6462598e31SEd Tanous             BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error");
655e577bc1SWilly Tu             return;
665e577bc1SWilly Tu         }
675e577bc1SWilly Tu 
685e577bc1SWilly Tu         nlohmann::json::array_t storages;
695e577bc1SWilly Tu         for (const std::string& storagePath : storageList)
705e577bc1SWilly Tu         {
715e577bc1SWilly Tu             std::string id =
725e577bc1SWilly Tu                 sdbusplus::message::object_path(storagePath).filename();
735e577bc1SWilly Tu             if (id.empty())
745e577bc1SWilly Tu             {
755e577bc1SWilly Tu                 continue;
765e577bc1SWilly Tu             }
775e577bc1SWilly Tu 
785e577bc1SWilly Tu             nlohmann::json::object_t storage;
79253f11b8SEd Tanous             storage["@odata.id"] =
80253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
81253f11b8SEd Tanous                                     BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
825e577bc1SWilly Tu             storages.emplace_back(std::move(storage));
835e577bc1SWilly Tu         }
845e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
855e577bc1SWilly Tu             storages.size();
865e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
875e577bc1SWilly Tu     });
885e577bc1SWilly Tu }
895e577bc1SWilly Tu 
905e577bc1SWilly Tu /**
91beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
92beeca0aeSGunnar Mills  *
93ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
94beeca0aeSGunnar Mills  *
95beeca0aeSGunnar Mills  * @return None.
96beeca0aeSGunnar Mills  */
getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)97ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
98beeca0aeSGunnar Mills {
991e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
1001e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1011e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1021e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1031e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
104ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1051e1e598dSJonathan Doman                                           const std::string& chassisState) {
106beeca0aeSGunnar Mills         if (ec)
107beeca0aeSGunnar Mills         {
108a6e5e0abSCarson Labrado             if (ec == boost::system::errc::host_unreachable)
109a6e5e0abSCarson Labrado             {
110a6e5e0abSCarson Labrado                 // Service not available, no error, just don't return
111a6e5e0abSCarson Labrado                 // chassis state info
11262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Service not available {}", ec);
113a6e5e0abSCarson Labrado                 return;
114a6e5e0abSCarson Labrado             }
11562598e31SEd Tanous             BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
116ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
117beeca0aeSGunnar Mills             return;
118beeca0aeSGunnar Mills         }
119beeca0aeSGunnar Mills 
12062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
121beeca0aeSGunnar Mills         // Verify Chassis State
122002d39b4SEd Tanous         if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
123beeca0aeSGunnar Mills         {
124ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "On";
125ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
126beeca0aeSGunnar Mills         }
1271e1e598dSJonathan Doman         else if (chassisState ==
128beeca0aeSGunnar Mills                  "xyz.openbmc_project.State.Chassis.PowerState.Off")
129beeca0aeSGunnar Mills         {
130ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "Off";
131ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
132beeca0aeSGunnar Mills         }
1331e1e598dSJonathan Doman     });
134beeca0aeSGunnar Mills }
135beeca0aeSGunnar Mills 
136c181942fSQiang XU /**
137c181942fSQiang XU  * Retrieves physical security properties over dbus
138c181942fSQiang XU  */
handlePhysicalSecurityGetSubTree(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)1397164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
1407164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
141e99073f5SGeorge Liu     const boost::system::error_code& ec,
1427164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
1437164bc62SChau Ly {
144c181942fSQiang XU     if (ec)
145c181942fSQiang XU     {
1464e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
147c181942fSQiang XU         //     mandatory property
14862598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
149c181942fSQiang XU         return;
150c181942fSQiang XU     }
151c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
152c181942fSQiang XU     for (const auto& object : subtree)
153c181942fSQiang XU     {
154840a9ffcSPatrick Williams         if (!object.second.empty())
155c181942fSQiang XU         {
15689144a3aSEd Tanous             const auto& service = object.second.front();
1577164bc62SChau Ly 
1587164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
1597164bc62SChau Ly 
1607164bc62SChau Ly             sdbusplus::asio::getProperty<std::string>(
1617164bc62SChau Ly                 *crow::connections::systemBus, service.first, object.first,
1627164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
1637164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
1647164bc62SChau Ly                             const std::string& value) {
1657164bc62SChau Ly                 if (ec1)
1667164bc62SChau Ly                 {
1677164bc62SChau Ly                     // do not add err msg in redfish response, because this is
1687164bc62SChau Ly                     // not
1697164bc62SChau Ly                     //     mandatory property
1707164bc62SChau Ly                     BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
1717164bc62SChau Ly                     return;
1727164bc62SChau Ly                 }
1737164bc62SChau Ly                 asyncResp->res
1747164bc62SChau Ly                     .jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
1757164bc62SChau Ly                 asyncResp->res
1767164bc62SChau Ly                     .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
1777164bc62SChau Ly             });
1787164bc62SChau Ly 
179c181942fSQiang XU             return;
180c181942fSQiang XU         }
181c181942fSQiang XU     }
182c181942fSQiang XU }
183c181942fSQiang XU 
handleChassisCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)184cf7eba09SNan Zhou inline void handleChassisCollectionGet(
185cf7eba09SNan Zhou     App& app, const crow::Request& req,
186cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1871abe55efSEd Tanous {
1883ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18945ca1b86SEd Tanous     {
19045ca1b86SEd Tanous         return;
19145ca1b86SEd Tanous     }
1928d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
1938d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
1948d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
1958d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
196e37f8451SRapkiewicz, Pawel 
1977a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
1987a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
1997a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
20002f6ff19SGunnar Mills     collection_util::getCollectionMembers(
20136b5f1edSLakshmi Yadlapati         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces,
20236b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
203cf7eba09SNan Zhou }
204cf7eba09SNan Zhou 
getChassisContainedBy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & upstreamChassisPaths)205a5617496SJie Yang inline void getChassisContainedBy(
206a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
207a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
208*28ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths)
209a5617496SJie Yang {
210a5617496SJie Yang     if (ec)
211a5617496SJie Yang     {
212a5617496SJie Yang         if (ec.value() != EBADR)
213a5617496SJie Yang         {
21462598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
215a5617496SJie Yang             messages::internalError(asyncResp->res);
216a5617496SJie Yang         }
217a5617496SJie Yang         return;
218a5617496SJie Yang     }
219a5617496SJie Yang     if (upstreamChassisPaths.empty())
220a5617496SJie Yang     {
221a5617496SJie Yang         return;
222a5617496SJie Yang     }
223a5617496SJie Yang     if (upstreamChassisPaths.size() > 1)
224a5617496SJie Yang     {
2258ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId);
226a5617496SJie Yang         messages::internalError(asyncResp->res);
227a5617496SJie Yang         return;
228a5617496SJie Yang     }
229a5617496SJie Yang 
230a5617496SJie Yang     sdbusplus::message::object_path upstreamChassisPath(
231a5617496SJie Yang         upstreamChassisPaths[0]);
232a5617496SJie Yang     std::string upstreamChassis = upstreamChassisPath.filename();
233a5617496SJie Yang     if (upstreamChassis.empty())
234a5617496SJie Yang     {
23562598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
23662598e31SEd Tanous                            upstreamChassisPath.str, chassisId);
237a5617496SJie Yang         return;
238a5617496SJie Yang     }
239a5617496SJie Yang 
240a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
241a5617496SJie Yang         boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
242a5617496SJie Yang }
243a5617496SJie Yang 
getChassisContains(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & downstreamChassisPaths)244a5617496SJie Yang inline void getChassisContains(
245a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
246a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
247*28ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths)
248a5617496SJie Yang {
249a5617496SJie Yang     if (ec)
250a5617496SJie Yang     {
251a5617496SJie Yang         if (ec.value() != EBADR)
252a5617496SJie Yang         {
25362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
254a5617496SJie Yang             messages::internalError(asyncResp->res);
255a5617496SJie Yang         }
256a5617496SJie Yang         return;
257a5617496SJie Yang     }
258a5617496SJie Yang     if (downstreamChassisPaths.empty())
259a5617496SJie Yang     {
260a5617496SJie Yang         return;
261a5617496SJie Yang     }
262a5617496SJie Yang     nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
263a5617496SJie Yang     if (!jValue.is_array())
264a5617496SJie Yang     {
265a5617496SJie Yang         // Create the array if it was empty
266a5617496SJie Yang         jValue = nlohmann::json::array();
267a5617496SJie Yang     }
268a5617496SJie Yang     for (const auto& p : downstreamChassisPaths)
269a5617496SJie Yang     {
270a5617496SJie Yang         sdbusplus::message::object_path downstreamChassisPath(p);
271a5617496SJie Yang         std::string downstreamChassis = downstreamChassisPath.filename();
272a5617496SJie Yang         if (downstreamChassis.empty())
273a5617496SJie Yang         {
27462598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
27562598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
276a5617496SJie Yang             continue;
277a5617496SJie Yang         }
278a5617496SJie Yang         nlohmann::json link;
279a5617496SJie Yang         link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}",
280a5617496SJie Yang                                                 downstreamChassis);
281a5617496SJie Yang         jValue.push_back(std::move(link));
282a5617496SJie Yang     }
283a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
284a5617496SJie Yang }
285a5617496SJie Yang 
286a5617496SJie Yang inline void
getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & chassisPath)287a5617496SJie Yang     getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
288a5617496SJie Yang                            const std::string& chassisId,
289a5617496SJie Yang                            const std::string& chassisPath)
290a5617496SJie Yang {
29162598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
292a5617496SJie Yang 
293*28ee563eSMyung Bae     constexpr std::array<std::string_view, 2> interfaces{
294*28ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Board",
295*28ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Chassis"};
296*28ee563eSMyung Bae 
297*28ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
298a5617496SJie Yang         chassisPath + "/contained_by",
299*28ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
300*28ee563eSMyung Bae         interfaces,
301a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
302a5617496SJie Yang 
303*28ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
304a5617496SJie Yang         chassisPath + "/containing",
305*28ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
306*28ee563eSMyung Bae         interfaces, std::bind_front(getChassisContains, asyncResp, chassisId));
307a5617496SJie Yang }
308a5617496SJie Yang 
309cf7eba09SNan Zhou /**
310cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
311cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
312cf7eba09SNan Zhou  */
requestRoutesChassisCollection(App & app)313cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
314cf7eba09SNan Zhou {
315cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
316cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
317cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
318cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
31962d5e2e4SEd Tanous }
320e37f8451SRapkiewicz, Pawel 
321308f70c7SWilly Tu inline void
getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & connectionName,const std::string & path)322308f70c7SWilly Tu     getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
323308f70c7SWilly Tu                            const std::string& connectionName,
324308f70c7SWilly Tu                            const std::string& path)
325308f70c7SWilly Tu {
3261e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3271e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3281e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3295e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3301e1e598dSJonathan Doman                     const std::string& property) {
331308f70c7SWilly Tu         if (ec)
332308f70c7SWilly Tu         {
33362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for Location");
334308f70c7SWilly Tu             messages::internalError(asyncResp->res);
335308f70c7SWilly Tu             return;
336308f70c7SWilly Tu         }
337308f70c7SWilly Tu 
338002d39b4SEd Tanous         asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3391e1e598dSJonathan Doman             property;
3401e1e598dSJonathan Doman     });
341308f70c7SWilly Tu }
342308f70c7SWilly Tu 
getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & connectionName,const std::string & path)343308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
344308f70c7SWilly Tu                            const std::string& connectionName,
345308f70c7SWilly Tu                            const std::string& path)
346308f70c7SWilly Tu {
3471e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3481e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3491e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
3505e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3511e1e598dSJonathan Doman                     const std::string& chassisUUID) {
352308f70c7SWilly Tu         if (ec)
353308f70c7SWilly Tu         {
35462598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for UUID");
355308f70c7SWilly Tu             messages::internalError(asyncResp->res);
356308f70c7SWilly Tu             return;
357308f70c7SWilly Tu         }
3581e1e598dSJonathan Doman         asyncResp->res.jsonValue["UUID"] = chassisUUID;
3591e1e598dSJonathan Doman     });
360308f70c7SWilly Tu }
361308f70c7SWilly Tu 
handleDecoratorAssetProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & path,const dbus::utility::DBusPropertiesMap & propertiesList)3627164bc62SChau Ly inline void handleDecoratorAssetProperties(
36345ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3647164bc62SChau Ly     const std::string& chassisId, const std::string& path,
3657164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
366cf7eba09SNan Zhou {
3677164bc62SChau Ly     const std::string* partNumber = nullptr;
3687164bc62SChau Ly     const std::string* serialNumber = nullptr;
3697164bc62SChau Ly     const std::string* manufacturer = nullptr;
3707164bc62SChau Ly     const std::string* model = nullptr;
3717164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
3727164bc62SChau Ly 
3737164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
3747164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
3757164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
3767164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
3777164bc62SChau Ly 
3787164bc62SChau Ly     if (!success)
37945ca1b86SEd Tanous     {
3807164bc62SChau Ly         messages::internalError(asyncResp->res);
38145ca1b86SEd Tanous         return;
38245ca1b86SEd Tanous     }
383734bfe90SGunnar Mills 
3847164bc62SChau Ly     if (partNumber != nullptr)
3857164bc62SChau Ly     {
3867164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3877164bc62SChau Ly     }
3887164bc62SChau Ly 
3897164bc62SChau Ly     if (serialNumber != nullptr)
3907164bc62SChau Ly     {
3917164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3927164bc62SChau Ly     }
3937164bc62SChau Ly 
3947164bc62SChau Ly     if (manufacturer != nullptr)
3957164bc62SChau Ly     {
3967164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3977164bc62SChau Ly     }
3987164bc62SChau Ly 
3997164bc62SChau Ly     if (model != nullptr)
4007164bc62SChau Ly     {
4017164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
4027164bc62SChau Ly     }
4037164bc62SChau Ly 
4047164bc62SChau Ly     // SparePartNumber is optional on D-Bus
4057164bc62SChau Ly     // so skip if it is empty
4067164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
4077164bc62SChau Ly     {
4087164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4097164bc62SChau Ly     }
4107164bc62SChau Ly 
4117164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4127164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
41325b54dbaSEd Tanous 
41425b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
41525b54dbaSEd Tanous     {
4167164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4177164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4187164bc62SChau Ly         // Power object
4197164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4207164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
42125b54dbaSEd Tanous     }
42225b54dbaSEd Tanous 
42325b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
42425b54dbaSEd Tanous     {
4257164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4267164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4277164bc62SChau Ly                                 chassisId);
4287164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
42925b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
43025b54dbaSEd Tanous                                 chassisId);
4317164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4327164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4337164bc62SChau Ly                                 chassisId);
43425b54dbaSEd Tanous     }
4357164bc62SChau Ly     // SensorCollection
4367164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4377164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
4387164bc62SChau Ly     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
4397164bc62SChau Ly 
4407164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4417164bc62SChau Ly     nlohmann::json::object_t system;
442253f11b8SEd Tanous     system["@odata.id"] = std::format("/redfish/v1/Systems/{}",
443253f11b8SEd Tanous                                       BMCWEB_REDFISH_SYSTEM_URI_NAME);
4447164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4457164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4467164bc62SChau Ly         std::move(computerSystems);
4477164bc62SChau Ly 
4487164bc62SChau Ly     nlohmann::json::array_t managedBy;
4497164bc62SChau Ly     nlohmann::json::object_t manager;
450253f11b8SEd Tanous     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
451253f11b8SEd Tanous                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
4527164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4537164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4547164bc62SChau Ly     getChassisState(asyncResp);
4557164bc62SChau Ly     getStorageLink(asyncResp, path);
4567164bc62SChau Ly }
4577164bc62SChau Ly 
handleChassisGetSubTree(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)4587164bc62SChau Ly inline void handleChassisGetSubTree(
4597164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4607164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
4617164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
4627164bc62SChau Ly {
46362d5e2e4SEd Tanous     if (ec)
4641abe55efSEd Tanous     {
46562598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
466f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
467daf36e2eSEd Tanous         return;
468daf36e2eSEd Tanous     }
469daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
470cf7eba09SNan Zhou     for (const std::pair<
471cf7eba09SNan Zhou              std::string,
472cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
4731214b7e7SGunnar Mills              object : subtree)
4741abe55efSEd Tanous     {
475daf36e2eSEd Tanous         const std::string& path = object.first;
476cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
4771214b7e7SGunnar Mills             connectionNames = object.second;
4787e860f15SJohn Edward Broadbent 
479997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
480997093ebSGeorge Liu         if (objPath.filename() != chassisId)
4811abe55efSEd Tanous         {
482daf36e2eSEd Tanous             continue;
483daf36e2eSEd Tanous         }
48426f03899SShawn McCarney 
485a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
486a5617496SJie Yang 
48726f6976fSEd Tanous         if (connectionNames.empty())
4881abe55efSEd Tanous         {
48962598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
490e0d918bcSEd Tanous             continue;
491daf36e2eSEd Tanous         }
492e0d918bcSEd Tanous 
4937164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
49449c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
495ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
49649c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
49749c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
498cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
4997164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
5007164bc62SChau Ly                                 chassisId);
5011476687dSEd Tanous         asyncResp->res
502cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
503ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
504ef4c65b7SEd Tanous                                 chassisId);
5056c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
5066c3e9451SGeorge Liu             path + "/drive",
5077164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
5086c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
50992903bd4SJohn Edward Broadbent             if (ec3 || resp.empty())
51092903bd4SJohn Edward Broadbent             {
51192903bd4SJohn Edward Broadbent                 return; // no drives = no failures
51292903bd4SJohn Edward Broadbent             }
51392903bd4SJohn Edward Broadbent 
51492903bd4SJohn Edward Broadbent             nlohmann::json reference;
5157164bc62SChau Ly             reference["@odata.id"] =
5167164bc62SChau Ly                 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
51792903bd4SJohn Edward Broadbent             asyncResp->res.jsonValue["Drives"] = std::move(reference);
51892903bd4SJohn Edward Broadbent         });
51992903bd4SJohn Edward Broadbent 
520002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
5211c8fba97SJames Feist 
5227164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
523e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
524e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
5251c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5260fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5271c8fba97SJames Feist 
528476b9cc5STejas Patil         const std::string assetTagInterface =
5290fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
530523d4868SLogananth Sundararaj         const std::string replaceableInterface =
531523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
532b4d593f1SCarson Labrado         const std::string revisionInterface =
533b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
534523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
535523d4868SLogananth Sundararaj         {
536523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
537476b9cc5STejas Patil             {
5381e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
539002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
540002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
5417164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5421e1e598dSJonathan Doman                                            const std::string& property) {
5438a592810SEd Tanous                     if (ec2)
544476b9cc5STejas Patil                     {
5457164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBus response error for AssetTag: {}",
5467164bc62SChau Ly                                          ec2);
547476b9cc5STejas Patil                         messages::internalError(asyncResp->res);
548476b9cc5STejas Patil                         return;
549476b9cc5STejas Patil                     }
550002d39b4SEd Tanous                     asyncResp->res.jsonValue["AssetTag"] = property;
5511e1e598dSJonathan Doman                 });
552476b9cc5STejas Patil             }
553523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
554523d4868SLogananth Sundararaj             {
555523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
556523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
557523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
5587164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
559523d4868SLogananth Sundararaj                                            const bool property) {
560523d4868SLogananth Sundararaj                     if (ec2)
561523d4868SLogananth Sundararaj                     {
56262598e31SEd Tanous                         BMCWEB_LOG_ERROR(
5637164bc62SChau Ly                             "DBus response error for HotPluggable: {}", ec2);
564523d4868SLogananth Sundararaj                         messages::internalError(asyncResp->res);
565523d4868SLogananth Sundararaj                         return;
566523d4868SLogananth Sundararaj                     }
567523d4868SLogananth Sundararaj                     asyncResp->res.jsonValue["HotPluggable"] = property;
568523d4868SLogananth Sundararaj                 });
569523d4868SLogananth Sundararaj             }
570b4d593f1SCarson Labrado             else if (interface == revisionInterface)
571b4d593f1SCarson Labrado             {
572b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
573b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
574b4d593f1SCarson Labrado                     revisionInterface, "Version",
575b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
576b4d593f1SCarson Labrado                                            const std::string& property) {
577b4d593f1SCarson Labrado                     if (ec2)
578b4d593f1SCarson Labrado                     {
579b4d593f1SCarson Labrado                         BMCWEB_LOG_ERROR("DBus response error for Version: {}",
580b4d593f1SCarson Labrado                                          ec2);
581b4d593f1SCarson Labrado                         messages::internalError(asyncResp->res);
582b4d593f1SCarson Labrado                         return;
583b4d593f1SCarson Labrado                     }
584b4d593f1SCarson Labrado                     asyncResp->res.jsonValue["Version"] = property;
585b4d593f1SCarson Labrado                 });
586b4d593f1SCarson Labrado             }
587523d4868SLogananth Sundararaj         }
588476b9cc5STejas Patil 
5891c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
5901c8fba97SJames Feist         {
5917164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
5921c8fba97SJames Feist             {
5931c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
59459a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
5951c8fba97SJames Feist                 break;
5961c8fba97SJames Feist             }
5971c8fba97SJames Feist         }
5981c8fba97SJames Feist 
59986d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
60086d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
60186d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
6027164bc62SChau Ly             [asyncResp, chassisId,
6037164bc62SChau Ly              path](const boost::system::error_code&,
604cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
6057164bc62SChau Ly             handleDecoratorAssetProperties(asyncResp, chassisId, path,
6067164bc62SChau Ly                                            propertiesList);
60786d89ed7SKrzysztof Grobelny         });
6082c37b4b0SSharad Yadav 
609308f70c7SWilly Tu         for (const auto& interface : interfaces2)
6102c37b4b0SSharad Yadav         {
611308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
6122c37b4b0SSharad Yadav             {
613308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
6142c37b4b0SSharad Yadav             }
615cf7eba09SNan Zhou             else if (interface ==
6160fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6172c37b4b0SSharad Yadav             {
618002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6192c37b4b0SSharad Yadav             }
6202c37b4b0SSharad Yadav         }
6212c37b4b0SSharad Yadav 
622daf36e2eSEd Tanous         return;
623daf36e2eSEd Tanous     }
624e0d918bcSEd Tanous 
625daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
626d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6277164bc62SChau Ly }
628c181942fSQiang XU 
6297164bc62SChau Ly inline void
handleChassisGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)6307164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
6317164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6327164bc62SChau Ly                      const std::string& chassisId)
6337164bc62SChau Ly {
6347164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6357164bc62SChau Ly     {
6367164bc62SChau Ly         return;
6377164bc62SChau Ly     }
6387164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
6397164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
6407164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
6417164bc62SChau Ly 
6427164bc62SChau Ly     dbus::utility::getSubTree(
6437164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
6447164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6457164bc62SChau Ly 
6467164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6477164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6487164bc62SChau Ly 
6497164bc62SChau Ly     dbus::utility::getSubTree(
6507164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
6517164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
652cf7eba09SNan Zhou }
6531c8fba97SJames Feist 
654cf7eba09SNan Zhou inline void
handleChassisPatch(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & param)655cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
6567e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
657cf7eba09SNan Zhou                        const std::string& param)
658cf7eba09SNan Zhou {
6593ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
66045ca1b86SEd Tanous     {
66145ca1b86SEd Tanous         return;
66245ca1b86SEd Tanous     }
6639f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
6641c8fba97SJames Feist     std::optional<std::string> indicatorLed;
6651c8fba97SJames Feist 
6667e860f15SJohn Edward Broadbent     if (param.empty())
6671c8fba97SJames Feist     {
6681c8fba97SJames Feist         return;
6691c8fba97SJames Feist     }
6701c8fba97SJames Feist 
67115ed6780SWilly Tu     if (!json_util::readJsonPatch(
6727e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
6737e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
6741c8fba97SJames Feist     {
6751c8fba97SJames Feist         return;
6761c8fba97SJames Feist     }
6771c8fba97SJames Feist 
6789f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6799f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6801c8fba97SJames Feist     {
6811c8fba97SJames Feist         return; // delete this when we support more patch properties
6821c8fba97SJames Feist     }
683d6aa0093SGunnar Mills     if (indicatorLed)
684d6aa0093SGunnar Mills     {
6857e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6867e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6870fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
688d6aa0093SGunnar Mills     }
6891c8fba97SJames Feist 
690e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
6911c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
6921c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
6931c8fba97SJames Feist 
6947e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
6951c8fba97SJames Feist 
696e99073f5SGeorge Liu     dbus::utility::getSubTree(
697e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
698cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
6995e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
700b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7011c8fba97SJames Feist         if (ec)
7021c8fba97SJames Feist         {
70362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
7041c8fba97SJames Feist             messages::internalError(asyncResp->res);
7051c8fba97SJames Feist             return;
7061c8fba97SJames Feist         }
7071c8fba97SJames Feist 
7081c8fba97SJames Feist         // Iterate over all retrieved ObjectPaths.
709cf7eba09SNan Zhou         for (const std::pair<
710cf7eba09SNan Zhou                  std::string,
711cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
7121214b7e7SGunnar Mills                  object : subtree)
7131c8fba97SJames Feist         {
7141c8fba97SJames Feist             const std::string& path = object.first;
715cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
7161214b7e7SGunnar Mills                 connectionNames = object.second;
7171c8fba97SJames Feist 
718997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
719997093ebSGeorge Liu             if (objPath.filename() != chassisId)
7201c8fba97SJames Feist             {
7211c8fba97SJames Feist                 continue;
7221c8fba97SJames Feist             }
7231c8fba97SJames Feist 
72426f6976fSEd Tanous             if (connectionNames.empty())
7251c8fba97SJames Feist             {
72662598e31SEd Tanous                 BMCWEB_LOG_ERROR("Got 0 Connection names");
7271c8fba97SJames Feist                 continue;
7281c8fba97SJames Feist             }
7291c8fba97SJames Feist 
73023a21a1cSEd Tanous             const std::vector<std::string>& interfaces3 =
7311c8fba97SJames Feist                 connectionNames[0].second;
7321c8fba97SJames Feist 
733e5ae9c1cSGeorge Liu             const std::array<const char*, 3> hasIndicatorLed = {
734e5ae9c1cSGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Chassis",
7351c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
7360fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7371c8fba97SJames Feist             bool indicatorChassis = false;
7381c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
7391c8fba97SJames Feist             {
7403544d2a7SEd Tanous                 if (std::ranges::find(interfaces3, interface) !=
7413544d2a7SEd Tanous                     interfaces3.end())
7421c8fba97SJames Feist                 {
7431c8fba97SJames Feist                     indicatorChassis = true;
7441c8fba97SJames Feist                     break;
7451c8fba97SJames Feist                 }
7461c8fba97SJames Feist             }
7479f8bfa7cSGunnar Mills             if (locationIndicatorActive)
7489f8bfa7cSGunnar Mills             {
7499f8bfa7cSGunnar Mills                 if (indicatorChassis)
7509f8bfa7cSGunnar Mills                 {
75159a17e4fSGeorge Liu                     setSystemLocationIndicatorActive(asyncResp,
752002d39b4SEd Tanous                                                      *locationIndicatorActive);
7539f8bfa7cSGunnar Mills                 }
7549f8bfa7cSGunnar Mills                 else
7559f8bfa7cSGunnar Mills                 {
756002d39b4SEd Tanous                     messages::propertyUnknown(asyncResp->res,
757002d39b4SEd Tanous                                               "LocationIndicatorActive");
7589f8bfa7cSGunnar Mills                 }
7599f8bfa7cSGunnar Mills             }
7609f8bfa7cSGunnar Mills             if (indicatorLed)
7619f8bfa7cSGunnar Mills             {
7621c8fba97SJames Feist                 if (indicatorChassis)
7631c8fba97SJames Feist                 {
764f23b7296SEd Tanous                     setIndicatorLedState(asyncResp, *indicatorLed);
7651c8fba97SJames Feist                 }
7661c8fba97SJames Feist                 else
7671c8fba97SJames Feist                 {
768cf7eba09SNan Zhou                     messages::propertyUnknown(asyncResp->res, "IndicatorLED");
7691c8fba97SJames Feist                 }
7701c8fba97SJames Feist             }
7711c8fba97SJames Feist             return;
7721c8fba97SJames Feist         }
7731c8fba97SJames Feist 
774d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
775e99073f5SGeorge Liu     });
776cf7eba09SNan Zhou }
777cf7eba09SNan Zhou 
778cf7eba09SNan Zhou /**
779cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
780cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
781cf7eba09SNan Zhou  */
requestRoutesChassis(App & app)782cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
783cf7eba09SNan Zhou {
784cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
785cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
786cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
787cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
788cf7eba09SNan Zhou 
789cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
790cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
791cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
792cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
7931c8fba97SJames Feist }
794dd99e04bSP.K. Lee 
7958d1b46d7Szhanghch05 inline void
doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)7968d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
797dd99e04bSP.K. Lee {
7987a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
799c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
800c3b3c92aSVijay Khemka 
801c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
8027a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
8037a1dbc48SGeorge Liu         "/", 0, interfaces,
804b9d36b47SEd Tanous         [asyncResp](
8057a1dbc48SGeorge Liu             const boost::system::error_code& ec,
806b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
807c3b3c92aSVijay Khemka         if (ec)
808c3b3c92aSVijay Khemka         {
80962598e31SEd Tanous             BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
810c3b3c92aSVijay Khemka             messages::internalError(asyncResp->res);
811c3b3c92aSVijay Khemka             return;
812c3b3c92aSVijay Khemka         }
813c3b3c92aSVijay Khemka 
814dd99e04bSP.K. Lee         const char* processName = "xyz.openbmc_project.State.Chassis";
815dd99e04bSP.K. Lee         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
816dd99e04bSP.K. Lee         const char* destProperty = "RequestedPowerTransition";
817dd99e04bSP.K. Lee         const std::string propertyValue =
818dd99e04bSP.K. Lee             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
819002d39b4SEd Tanous         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
820c3b3c92aSVijay Khemka 
821c3b3c92aSVijay Khemka         /* Look for system reset chassis path */
8223544d2a7SEd Tanous         if ((std::ranges::find(chassisList, objectPath)) == chassisList.end())
823c3b3c92aSVijay Khemka         {
824c3b3c92aSVijay Khemka             /* We prefer to reset the full chassis_system, but if it doesn't
825c3b3c92aSVijay Khemka              * exist on some platforms, fall back to a host-only power reset
826c3b3c92aSVijay Khemka              */
827c3b3c92aSVijay Khemka             objectPath = "/xyz/openbmc_project/state/chassis0";
828c3b3c92aSVijay Khemka         }
829dd99e04bSP.K. Lee 
830e93abac6SGinu George         setDbusProperty(asyncResp, "ResetType", processName, objectPath,
831e93abac6SGinu George                         interfaceName, destProperty, propertyValue);
8327a1dbc48SGeorge Liu     });
833dd99e04bSP.K. Lee }
834dd99e04bSP.K. Lee 
handleChassisResetActionInfoPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)835cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
836cf7eba09SNan Zhou     App& app, const crow::Request& req,
8377e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
838cf7eba09SNan Zhou     const std::string& /*chassisId*/)
839cf7eba09SNan Zhou {
8403ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
84145ca1b86SEd Tanous     {
84245ca1b86SEd Tanous         return;
84345ca1b86SEd Tanous     }
84462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
845dd99e04bSP.K. Lee 
846dd99e04bSP.K. Lee     std::string resetType;
847dd99e04bSP.K. Lee 
848cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
849dd99e04bSP.K. Lee     {
850dd99e04bSP.K. Lee         return;
851dd99e04bSP.K. Lee     }
852dd99e04bSP.K. Lee 
853dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
854dd99e04bSP.K. Lee     {
85562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
856002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
857002d39b4SEd Tanous                                               "ResetType");
858dd99e04bSP.K. Lee 
859dd99e04bSP.K. Lee         return;
860dd99e04bSP.K. Lee     }
861dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
862dd99e04bSP.K. Lee }
8631cb1a9e6SAppaRao Puli 
8641cb1a9e6SAppaRao Puli /**
865cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
866cf7eba09SNan Zhou  * action.
867cf7eba09SNan Zhou  * Function handles POST method request.
868cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8691cb1a9e6SAppaRao Puli  */
870cf7eba09SNan Zhou 
requestRoutesChassisResetAction(App & app)871cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8721cb1a9e6SAppaRao Puli {
873cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
874cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
875cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
876cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
877cf7eba09SNan Zhou }
878cf7eba09SNan Zhou 
handleChassisResetActionInfoGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)879cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
880cf7eba09SNan Zhou     App& app, const crow::Request& req,
8817e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
882cf7eba09SNan Zhou     const std::string& chassisId)
883cf7eba09SNan Zhou {
8843ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
8851cb1a9e6SAppaRao Puli     {
88645ca1b86SEd Tanous         return;
88745ca1b86SEd Tanous     }
888cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
889ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
890ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
8911476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
8921476687dSEd Tanous 
8931476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
8945b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
8955b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
8965b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
8975b9e95a1SNan Zhou     parameter["Required"] = true;
8985b9e95a1SNan Zhou     parameter["DataType"] = "String";
8991476687dSEd Tanous     nlohmann::json::array_t allowed;
900ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
9015b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
902ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
9035b9e95a1SNan Zhou 
9041476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
905cf7eba09SNan Zhou }
906cf7eba09SNan Zhou 
907cf7eba09SNan Zhou /**
908cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
909cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
910cf7eba09SNan Zhou  */
requestRoutesChassisResetActionInfo(App & app)911cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
912cf7eba09SNan Zhou {
913cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
914cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
915cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
916cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9171cb1a9e6SAppaRao Puli }
9181cb1a9e6SAppaRao Puli 
919e37f8451SRapkiewicz, Pawel } // namespace redfish
920