xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 25b54dba775b31021a3a4677eb79e9771bcb97f7)
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  */
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;
795e577bc1SWilly Tu             storage["@odata.id"] = boost::urls::format(
805e577bc1SWilly Tu                 "/redfish/v1/Systems/system/Storage/{}", id);
815e577bc1SWilly Tu             storages.emplace_back(std::move(storage));
825e577bc1SWilly Tu         }
835e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
845e577bc1SWilly Tu             storages.size();
855e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
865e577bc1SWilly Tu     });
875e577bc1SWilly Tu }
885e577bc1SWilly Tu 
895e577bc1SWilly Tu /**
90beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
91beeca0aeSGunnar Mills  *
92ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
93beeca0aeSGunnar Mills  *
94beeca0aeSGunnar Mills  * @return None.
95beeca0aeSGunnar Mills  */
96ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
97beeca0aeSGunnar Mills {
981e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
991e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1001e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1011e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1021e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
103ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1041e1e598dSJonathan Doman                                           const std::string& chassisState) {
105beeca0aeSGunnar Mills         if (ec)
106beeca0aeSGunnar Mills         {
107a6e5e0abSCarson Labrado             if (ec == boost::system::errc::host_unreachable)
108a6e5e0abSCarson Labrado             {
109a6e5e0abSCarson Labrado                 // Service not available, no error, just don't return
110a6e5e0abSCarson Labrado                 // chassis state info
11162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Service not available {}", ec);
112a6e5e0abSCarson Labrado                 return;
113a6e5e0abSCarson Labrado             }
11462598e31SEd Tanous             BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
115ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
116beeca0aeSGunnar Mills             return;
117beeca0aeSGunnar Mills         }
118beeca0aeSGunnar Mills 
11962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
120beeca0aeSGunnar Mills         // Verify Chassis State
121002d39b4SEd Tanous         if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
122beeca0aeSGunnar Mills         {
123ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "On";
124ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
125beeca0aeSGunnar Mills         }
1261e1e598dSJonathan Doman         else if (chassisState ==
127beeca0aeSGunnar Mills                  "xyz.openbmc_project.State.Chassis.PowerState.Off")
128beeca0aeSGunnar Mills         {
129ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "Off";
130ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
131beeca0aeSGunnar Mills         }
1321e1e598dSJonathan Doman     });
133beeca0aeSGunnar Mills }
134beeca0aeSGunnar Mills 
135c181942fSQiang XU /**
136c181942fSQiang XU  * Retrieves physical security properties over dbus
137c181942fSQiang XU  */
1387164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
1397164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
140e99073f5SGeorge Liu     const boost::system::error_code& ec,
1417164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
1427164bc62SChau Ly {
143c181942fSQiang XU     if (ec)
144c181942fSQiang XU     {
1454e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
146c181942fSQiang XU         //     mandatory property
14762598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
148c181942fSQiang XU         return;
149c181942fSQiang XU     }
150c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
151c181942fSQiang XU     for (const auto& object : subtree)
152c181942fSQiang XU     {
153840a9ffcSPatrick Williams         if (!object.second.empty())
154c181942fSQiang XU         {
15589144a3aSEd Tanous             const auto& service = object.second.front();
1567164bc62SChau Ly 
1577164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
1587164bc62SChau Ly 
1597164bc62SChau Ly             sdbusplus::asio::getProperty<std::string>(
1607164bc62SChau Ly                 *crow::connections::systemBus, service.first, object.first,
1617164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
1627164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
1637164bc62SChau Ly                             const std::string& value) {
1647164bc62SChau Ly                 if (ec1)
1657164bc62SChau Ly                 {
1667164bc62SChau Ly                     // do not add err msg in redfish response, because this is
1677164bc62SChau Ly                     // not
1687164bc62SChau Ly                     //     mandatory property
1697164bc62SChau Ly                     BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
1707164bc62SChau Ly                     return;
1717164bc62SChau Ly                 }
1727164bc62SChau Ly                 asyncResp->res
1737164bc62SChau Ly                     .jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
1747164bc62SChau Ly                 asyncResp->res
1757164bc62SChau Ly                     .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
1767164bc62SChau Ly             });
1777164bc62SChau Ly 
178c181942fSQiang XU             return;
179c181942fSQiang XU         }
180c181942fSQiang XU     }
181c181942fSQiang XU }
182c181942fSQiang XU 
183cf7eba09SNan Zhou inline void handleChassisCollectionGet(
184cf7eba09SNan Zhou     App& app, const crow::Request& req,
185cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1861abe55efSEd Tanous {
1873ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18845ca1b86SEd Tanous     {
18945ca1b86SEd Tanous         return;
19045ca1b86SEd Tanous     }
1918d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
1928d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
1938d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
1948d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
195e37f8451SRapkiewicz, Pawel 
1967a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
1977a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
1987a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
19902f6ff19SGunnar Mills     collection_util::getCollectionMembers(
20036b5f1edSLakshmi Yadlapati         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces,
20136b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
202cf7eba09SNan Zhou }
203cf7eba09SNan Zhou 
204a5617496SJie Yang inline void getChassisContainedBy(
205a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
206a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
207a5617496SJie Yang     const dbus::utility::MapperEndPoints& upstreamChassisPaths)
208a5617496SJie Yang {
209a5617496SJie Yang     if (ec)
210a5617496SJie Yang     {
211a5617496SJie Yang         if (ec.value() != EBADR)
212a5617496SJie Yang         {
21362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
214a5617496SJie Yang             messages::internalError(asyncResp->res);
215a5617496SJie Yang         }
216a5617496SJie Yang         return;
217a5617496SJie Yang     }
218a5617496SJie Yang     if (upstreamChassisPaths.empty())
219a5617496SJie Yang     {
220a5617496SJie Yang         return;
221a5617496SJie Yang     }
222a5617496SJie Yang     if (upstreamChassisPaths.size() > 1)
223a5617496SJie Yang     {
2248ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId);
225a5617496SJie Yang         messages::internalError(asyncResp->res);
226a5617496SJie Yang         return;
227a5617496SJie Yang     }
228a5617496SJie Yang 
229a5617496SJie Yang     sdbusplus::message::object_path upstreamChassisPath(
230a5617496SJie Yang         upstreamChassisPaths[0]);
231a5617496SJie Yang     std::string upstreamChassis = upstreamChassisPath.filename();
232a5617496SJie Yang     if (upstreamChassis.empty())
233a5617496SJie Yang     {
23462598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
23562598e31SEd Tanous                            upstreamChassisPath.str, chassisId);
236a5617496SJie Yang         return;
237a5617496SJie Yang     }
238a5617496SJie Yang 
239a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
240a5617496SJie Yang         boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
241a5617496SJie Yang }
242a5617496SJie Yang 
243a5617496SJie Yang inline void getChassisContains(
244a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
245a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
246a5617496SJie Yang     const dbus::utility::MapperEndPoints& downstreamChassisPaths)
247a5617496SJie Yang {
248a5617496SJie Yang     if (ec)
249a5617496SJie Yang     {
250a5617496SJie Yang         if (ec.value() != EBADR)
251a5617496SJie Yang         {
25262598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
253a5617496SJie Yang             messages::internalError(asyncResp->res);
254a5617496SJie Yang         }
255a5617496SJie Yang         return;
256a5617496SJie Yang     }
257a5617496SJie Yang     if (downstreamChassisPaths.empty())
258a5617496SJie Yang     {
259a5617496SJie Yang         return;
260a5617496SJie Yang     }
261a5617496SJie Yang     nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
262a5617496SJie Yang     if (!jValue.is_array())
263a5617496SJie Yang     {
264a5617496SJie Yang         // Create the array if it was empty
265a5617496SJie Yang         jValue = nlohmann::json::array();
266a5617496SJie Yang     }
267a5617496SJie Yang     for (const auto& p : downstreamChassisPaths)
268a5617496SJie Yang     {
269a5617496SJie Yang         sdbusplus::message::object_path downstreamChassisPath(p);
270a5617496SJie Yang         std::string downstreamChassis = downstreamChassisPath.filename();
271a5617496SJie Yang         if (downstreamChassis.empty())
272a5617496SJie Yang         {
27362598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
27462598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
275a5617496SJie Yang             continue;
276a5617496SJie Yang         }
277a5617496SJie Yang         nlohmann::json link;
278a5617496SJie Yang         link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}",
279a5617496SJie Yang                                                 downstreamChassis);
280a5617496SJie Yang         jValue.push_back(std::move(link));
281a5617496SJie Yang     }
282a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
283a5617496SJie Yang }
284a5617496SJie Yang 
285a5617496SJie Yang inline void
286a5617496SJie Yang     getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
287a5617496SJie Yang                            const std::string& chassisId,
288a5617496SJie Yang                            const std::string& chassisPath)
289a5617496SJie Yang {
29062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
291a5617496SJie Yang 
292a5617496SJie Yang     dbus::utility::getAssociationEndPoints(
293a5617496SJie Yang         chassisPath + "/contained_by",
294a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
295a5617496SJie Yang 
296a5617496SJie Yang     dbus::utility::getAssociationEndPoints(
297a5617496SJie Yang         chassisPath + "/containing",
298a5617496SJie Yang         std::bind_front(getChassisContains, asyncResp, chassisId));
299a5617496SJie Yang }
300a5617496SJie Yang 
301cf7eba09SNan Zhou /**
302cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
303cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
304cf7eba09SNan Zhou  */
305cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
306cf7eba09SNan Zhou {
307cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
308cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
309cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
310cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
31162d5e2e4SEd Tanous }
312e37f8451SRapkiewicz, Pawel 
313308f70c7SWilly Tu inline void
314308f70c7SWilly Tu     getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
315308f70c7SWilly Tu                            const std::string& connectionName,
316308f70c7SWilly Tu                            const std::string& path)
317308f70c7SWilly Tu {
3181e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3191e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3201e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3215e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3221e1e598dSJonathan Doman                     const std::string& property) {
323308f70c7SWilly Tu         if (ec)
324308f70c7SWilly Tu         {
32562598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for Location");
326308f70c7SWilly Tu             messages::internalError(asyncResp->res);
327308f70c7SWilly Tu             return;
328308f70c7SWilly Tu         }
329308f70c7SWilly Tu 
330002d39b4SEd Tanous         asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3311e1e598dSJonathan Doman             property;
3321e1e598dSJonathan Doman     });
333308f70c7SWilly Tu }
334308f70c7SWilly Tu 
335308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
336308f70c7SWilly Tu                            const std::string& connectionName,
337308f70c7SWilly Tu                            const std::string& path)
338308f70c7SWilly Tu {
3391e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3401e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3411e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
3425e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3431e1e598dSJonathan Doman                     const std::string& chassisUUID) {
344308f70c7SWilly Tu         if (ec)
345308f70c7SWilly Tu         {
34662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for UUID");
347308f70c7SWilly Tu             messages::internalError(asyncResp->res);
348308f70c7SWilly Tu             return;
349308f70c7SWilly Tu         }
3501e1e598dSJonathan Doman         asyncResp->res.jsonValue["UUID"] = chassisUUID;
3511e1e598dSJonathan Doman     });
352308f70c7SWilly Tu }
353308f70c7SWilly Tu 
3547164bc62SChau Ly inline void handleDecoratorAssetProperties(
35545ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3567164bc62SChau Ly     const std::string& chassisId, const std::string& path,
3577164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
358cf7eba09SNan Zhou {
3597164bc62SChau Ly     const std::string* partNumber = nullptr;
3607164bc62SChau Ly     const std::string* serialNumber = nullptr;
3617164bc62SChau Ly     const std::string* manufacturer = nullptr;
3627164bc62SChau Ly     const std::string* model = nullptr;
3637164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
3647164bc62SChau Ly 
3657164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
3667164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
3677164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
3687164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
3697164bc62SChau Ly 
3707164bc62SChau Ly     if (!success)
37145ca1b86SEd Tanous     {
3727164bc62SChau Ly         messages::internalError(asyncResp->res);
37345ca1b86SEd Tanous         return;
37445ca1b86SEd Tanous     }
375734bfe90SGunnar Mills 
3767164bc62SChau Ly     if (partNumber != nullptr)
3777164bc62SChau Ly     {
3787164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3797164bc62SChau Ly     }
3807164bc62SChau Ly 
3817164bc62SChau Ly     if (serialNumber != nullptr)
3827164bc62SChau Ly     {
3837164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3847164bc62SChau Ly     }
3857164bc62SChau Ly 
3867164bc62SChau Ly     if (manufacturer != nullptr)
3877164bc62SChau Ly     {
3887164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3897164bc62SChau Ly     }
3907164bc62SChau Ly 
3917164bc62SChau Ly     if (model != nullptr)
3927164bc62SChau Ly     {
3937164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
3947164bc62SChau Ly     }
3957164bc62SChau Ly 
3967164bc62SChau Ly     // SparePartNumber is optional on D-Bus
3977164bc62SChau Ly     // so skip if it is empty
3987164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
3997164bc62SChau Ly     {
4007164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4017164bc62SChau Ly     }
4027164bc62SChau Ly 
4037164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4047164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
405*25b54dbaSEd Tanous 
406*25b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
407*25b54dbaSEd Tanous     {
4087164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4097164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4107164bc62SChau Ly         // Power object
4117164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4127164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
413*25b54dbaSEd Tanous     }
414*25b54dbaSEd Tanous 
415*25b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
416*25b54dbaSEd Tanous     {
4177164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4187164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4197164bc62SChau Ly                                 chassisId);
4207164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
421*25b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
422*25b54dbaSEd Tanous                                 chassisId);
4237164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4247164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4257164bc62SChau Ly                                 chassisId);
426*25b54dbaSEd Tanous     }
4277164bc62SChau Ly     // SensorCollection
4287164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4297164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
4307164bc62SChau Ly     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
4317164bc62SChau Ly 
4327164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4337164bc62SChau Ly     nlohmann::json::object_t system;
4347164bc62SChau Ly     system["@odata.id"] = "/redfish/v1/Systems/system";
4357164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4367164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4377164bc62SChau Ly         std::move(computerSystems);
4387164bc62SChau Ly 
4397164bc62SChau Ly     nlohmann::json::array_t managedBy;
4407164bc62SChau Ly     nlohmann::json::object_t manager;
4417164bc62SChau Ly     manager["@odata.id"] = "/redfish/v1/Managers/bmc";
4427164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4437164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4447164bc62SChau Ly     getChassisState(asyncResp);
4457164bc62SChau Ly     getStorageLink(asyncResp, path);
4467164bc62SChau Ly }
4477164bc62SChau Ly 
4487164bc62SChau Ly inline void handleChassisGetSubTree(
4497164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4507164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
4517164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
4527164bc62SChau Ly {
45362d5e2e4SEd Tanous     if (ec)
4541abe55efSEd Tanous     {
45562598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
456f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
457daf36e2eSEd Tanous         return;
458daf36e2eSEd Tanous     }
459daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
460cf7eba09SNan Zhou     for (const std::pair<
461cf7eba09SNan Zhou              std::string,
462cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
4631214b7e7SGunnar Mills              object : subtree)
4641abe55efSEd Tanous     {
465daf36e2eSEd Tanous         const std::string& path = object.first;
466cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
4671214b7e7SGunnar Mills             connectionNames = object.second;
4687e860f15SJohn Edward Broadbent 
469997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
470997093ebSGeorge Liu         if (objPath.filename() != chassisId)
4711abe55efSEd Tanous         {
472daf36e2eSEd Tanous             continue;
473daf36e2eSEd Tanous         }
47426f03899SShawn McCarney 
475a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
476a5617496SJie Yang 
47726f6976fSEd Tanous         if (connectionNames.empty())
4781abe55efSEd Tanous         {
47962598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
480e0d918bcSEd Tanous             continue;
481daf36e2eSEd Tanous         }
482e0d918bcSEd Tanous 
4837164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
48449c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
485ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
48649c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
48749c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
488cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
4897164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
4907164bc62SChau Ly                                 chassisId);
4911476687dSEd Tanous         asyncResp->res
492cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
493ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
494ef4c65b7SEd Tanous                                 chassisId);
4956c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
4966c3e9451SGeorge Liu             path + "/drive",
4977164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
4986c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
49992903bd4SJohn Edward Broadbent             if (ec3 || resp.empty())
50092903bd4SJohn Edward Broadbent             {
50192903bd4SJohn Edward Broadbent                 return; // no drives = no failures
50292903bd4SJohn Edward Broadbent             }
50392903bd4SJohn Edward Broadbent 
50492903bd4SJohn Edward Broadbent             nlohmann::json reference;
5057164bc62SChau Ly             reference["@odata.id"] =
5067164bc62SChau Ly                 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
50792903bd4SJohn Edward Broadbent             asyncResp->res.jsonValue["Drives"] = std::move(reference);
50892903bd4SJohn Edward Broadbent         });
50992903bd4SJohn Edward Broadbent 
510002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
5111c8fba97SJames Feist 
5127164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
513e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
514e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
5151c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5160fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5171c8fba97SJames Feist 
518476b9cc5STejas Patil         const std::string assetTagInterface =
5190fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
520523d4868SLogananth Sundararaj         const std::string replaceableInterface =
521523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
522b4d593f1SCarson Labrado         const std::string revisionInterface =
523b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
524523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
525523d4868SLogananth Sundararaj         {
526523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
527476b9cc5STejas Patil             {
5281e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
529002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
530002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
5317164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5321e1e598dSJonathan Doman                                            const std::string& property) {
5338a592810SEd Tanous                     if (ec2)
534476b9cc5STejas Patil                     {
5357164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBus response error for AssetTag: {}",
5367164bc62SChau Ly                                          ec2);
537476b9cc5STejas Patil                         messages::internalError(asyncResp->res);
538476b9cc5STejas Patil                         return;
539476b9cc5STejas Patil                     }
540002d39b4SEd Tanous                     asyncResp->res.jsonValue["AssetTag"] = property;
5411e1e598dSJonathan Doman                 });
542476b9cc5STejas Patil             }
543523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
544523d4868SLogananth Sundararaj             {
545523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
546523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
547523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
5487164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
549523d4868SLogananth Sundararaj                                            const bool property) {
550523d4868SLogananth Sundararaj                     if (ec2)
551523d4868SLogananth Sundararaj                     {
55262598e31SEd Tanous                         BMCWEB_LOG_ERROR(
5537164bc62SChau Ly                             "DBus response error for HotPluggable: {}", ec2);
554523d4868SLogananth Sundararaj                         messages::internalError(asyncResp->res);
555523d4868SLogananth Sundararaj                         return;
556523d4868SLogananth Sundararaj                     }
557523d4868SLogananth Sundararaj                     asyncResp->res.jsonValue["HotPluggable"] = property;
558523d4868SLogananth Sundararaj                 });
559523d4868SLogananth Sundararaj             }
560b4d593f1SCarson Labrado             else if (interface == revisionInterface)
561b4d593f1SCarson Labrado             {
562b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
563b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
564b4d593f1SCarson Labrado                     revisionInterface, "Version",
565b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
566b4d593f1SCarson Labrado                                            const std::string& property) {
567b4d593f1SCarson Labrado                     if (ec2)
568b4d593f1SCarson Labrado                     {
569b4d593f1SCarson Labrado                         BMCWEB_LOG_ERROR("DBus response error for Version: {}",
570b4d593f1SCarson Labrado                                          ec2);
571b4d593f1SCarson Labrado                         messages::internalError(asyncResp->res);
572b4d593f1SCarson Labrado                         return;
573b4d593f1SCarson Labrado                     }
574b4d593f1SCarson Labrado                     asyncResp->res.jsonValue["Version"] = property;
575b4d593f1SCarson Labrado                 });
576b4d593f1SCarson Labrado             }
577523d4868SLogananth Sundararaj         }
578476b9cc5STejas Patil 
5791c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
5801c8fba97SJames Feist         {
5817164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
5821c8fba97SJames Feist             {
5831c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
58459a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
5851c8fba97SJames Feist                 break;
5861c8fba97SJames Feist             }
5871c8fba97SJames Feist         }
5881c8fba97SJames Feist 
58986d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
59086d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
59186d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
5927164bc62SChau Ly             [asyncResp, chassisId,
5937164bc62SChau Ly              path](const boost::system::error_code&,
594cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
5957164bc62SChau Ly             handleDecoratorAssetProperties(asyncResp, chassisId, path,
5967164bc62SChau Ly                                            propertiesList);
59786d89ed7SKrzysztof Grobelny         });
5982c37b4b0SSharad Yadav 
599308f70c7SWilly Tu         for (const auto& interface : interfaces2)
6002c37b4b0SSharad Yadav         {
601308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
6022c37b4b0SSharad Yadav             {
603308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
6042c37b4b0SSharad Yadav             }
605cf7eba09SNan Zhou             else if (interface ==
6060fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6072c37b4b0SSharad Yadav             {
608002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6092c37b4b0SSharad Yadav             }
6102c37b4b0SSharad Yadav         }
6112c37b4b0SSharad Yadav 
612daf36e2eSEd Tanous         return;
613daf36e2eSEd Tanous     }
614e0d918bcSEd Tanous 
615daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
616d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6177164bc62SChau Ly }
618c181942fSQiang XU 
6197164bc62SChau Ly inline void
6207164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
6217164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6227164bc62SChau Ly                      const std::string& chassisId)
6237164bc62SChau Ly {
6247164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6257164bc62SChau Ly     {
6267164bc62SChau Ly         return;
6277164bc62SChau Ly     }
6287164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
6297164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
6307164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
6317164bc62SChau Ly 
6327164bc62SChau Ly     dbus::utility::getSubTree(
6337164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
6347164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6357164bc62SChau Ly 
6367164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6377164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6387164bc62SChau Ly 
6397164bc62SChau Ly     dbus::utility::getSubTree(
6407164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
6417164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
642cf7eba09SNan Zhou }
6431c8fba97SJames Feist 
644cf7eba09SNan Zhou inline void
645cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
6467e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
647cf7eba09SNan Zhou                        const std::string& param)
648cf7eba09SNan Zhou {
6493ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65045ca1b86SEd Tanous     {
65145ca1b86SEd Tanous         return;
65245ca1b86SEd Tanous     }
6539f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
6541c8fba97SJames Feist     std::optional<std::string> indicatorLed;
6551c8fba97SJames Feist 
6567e860f15SJohn Edward Broadbent     if (param.empty())
6571c8fba97SJames Feist     {
6581c8fba97SJames Feist         return;
6591c8fba97SJames Feist     }
6601c8fba97SJames Feist 
66115ed6780SWilly Tu     if (!json_util::readJsonPatch(
6627e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
6637e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
6641c8fba97SJames Feist     {
6651c8fba97SJames Feist         return;
6661c8fba97SJames Feist     }
6671c8fba97SJames Feist 
6689f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6699f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6701c8fba97SJames Feist     {
6711c8fba97SJames Feist         return; // delete this when we support more patch properties
6721c8fba97SJames Feist     }
673d6aa0093SGunnar Mills     if (indicatorLed)
674d6aa0093SGunnar Mills     {
6757e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6767e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6770fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
678d6aa0093SGunnar Mills     }
6791c8fba97SJames Feist 
680e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
6811c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
6821c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
6831c8fba97SJames Feist 
6847e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
6851c8fba97SJames Feist 
686e99073f5SGeorge Liu     dbus::utility::getSubTree(
687e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
688cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
6895e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
690b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
6911c8fba97SJames Feist         if (ec)
6921c8fba97SJames Feist         {
69362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
6941c8fba97SJames Feist             messages::internalError(asyncResp->res);
6951c8fba97SJames Feist             return;
6961c8fba97SJames Feist         }
6971c8fba97SJames Feist 
6981c8fba97SJames Feist         // Iterate over all retrieved ObjectPaths.
699cf7eba09SNan Zhou         for (const std::pair<
700cf7eba09SNan Zhou                  std::string,
701cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
7021214b7e7SGunnar Mills                  object : subtree)
7031c8fba97SJames Feist         {
7041c8fba97SJames Feist             const std::string& path = object.first;
705cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
7061214b7e7SGunnar Mills                 connectionNames = object.second;
7071c8fba97SJames Feist 
708997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
709997093ebSGeorge Liu             if (objPath.filename() != chassisId)
7101c8fba97SJames Feist             {
7111c8fba97SJames Feist                 continue;
7121c8fba97SJames Feist             }
7131c8fba97SJames Feist 
71426f6976fSEd Tanous             if (connectionNames.empty())
7151c8fba97SJames Feist             {
71662598e31SEd Tanous                 BMCWEB_LOG_ERROR("Got 0 Connection names");
7171c8fba97SJames Feist                 continue;
7181c8fba97SJames Feist             }
7191c8fba97SJames Feist 
72023a21a1cSEd Tanous             const std::vector<std::string>& interfaces3 =
7211c8fba97SJames Feist                 connectionNames[0].second;
7221c8fba97SJames Feist 
723e5ae9c1cSGeorge Liu             const std::array<const char*, 3> hasIndicatorLed = {
724e5ae9c1cSGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Chassis",
7251c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
7260fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7271c8fba97SJames Feist             bool indicatorChassis = false;
7281c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
7291c8fba97SJames Feist             {
7303544d2a7SEd Tanous                 if (std::ranges::find(interfaces3, interface) !=
7313544d2a7SEd Tanous                     interfaces3.end())
7321c8fba97SJames Feist                 {
7331c8fba97SJames Feist                     indicatorChassis = true;
7341c8fba97SJames Feist                     break;
7351c8fba97SJames Feist                 }
7361c8fba97SJames Feist             }
7379f8bfa7cSGunnar Mills             if (locationIndicatorActive)
7389f8bfa7cSGunnar Mills             {
7399f8bfa7cSGunnar Mills                 if (indicatorChassis)
7409f8bfa7cSGunnar Mills                 {
74159a17e4fSGeorge Liu                     setSystemLocationIndicatorActive(asyncResp,
742002d39b4SEd Tanous                                                      *locationIndicatorActive);
7439f8bfa7cSGunnar Mills                 }
7449f8bfa7cSGunnar Mills                 else
7459f8bfa7cSGunnar Mills                 {
746002d39b4SEd Tanous                     messages::propertyUnknown(asyncResp->res,
747002d39b4SEd Tanous                                               "LocationIndicatorActive");
7489f8bfa7cSGunnar Mills                 }
7499f8bfa7cSGunnar Mills             }
7509f8bfa7cSGunnar Mills             if (indicatorLed)
7519f8bfa7cSGunnar Mills             {
7521c8fba97SJames Feist                 if (indicatorChassis)
7531c8fba97SJames Feist                 {
754f23b7296SEd Tanous                     setIndicatorLedState(asyncResp, *indicatorLed);
7551c8fba97SJames Feist                 }
7561c8fba97SJames Feist                 else
7571c8fba97SJames Feist                 {
758cf7eba09SNan Zhou                     messages::propertyUnknown(asyncResp->res, "IndicatorLED");
7591c8fba97SJames Feist                 }
7601c8fba97SJames Feist             }
7611c8fba97SJames Feist             return;
7621c8fba97SJames Feist         }
7631c8fba97SJames Feist 
764d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
765e99073f5SGeorge Liu     });
766cf7eba09SNan Zhou }
767cf7eba09SNan Zhou 
768cf7eba09SNan Zhou /**
769cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
770cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
771cf7eba09SNan Zhou  */
772cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
773cf7eba09SNan Zhou {
774cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
775cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
776cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
777cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
778cf7eba09SNan Zhou 
779cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
780cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
781cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
782cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
7831c8fba97SJames Feist }
784dd99e04bSP.K. Lee 
7858d1b46d7Szhanghch05 inline void
7868d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
787dd99e04bSP.K. Lee {
7887a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
789c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
790c3b3c92aSVijay Khemka 
791c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
7927a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
7937a1dbc48SGeorge Liu         "/", 0, interfaces,
794b9d36b47SEd Tanous         [asyncResp](
7957a1dbc48SGeorge Liu             const boost::system::error_code& ec,
796b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
797c3b3c92aSVijay Khemka         if (ec)
798c3b3c92aSVijay Khemka         {
79962598e31SEd Tanous             BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
800c3b3c92aSVijay Khemka             messages::internalError(asyncResp->res);
801c3b3c92aSVijay Khemka             return;
802c3b3c92aSVijay Khemka         }
803c3b3c92aSVijay Khemka 
804dd99e04bSP.K. Lee         const char* processName = "xyz.openbmc_project.State.Chassis";
805dd99e04bSP.K. Lee         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
806dd99e04bSP.K. Lee         const char* destProperty = "RequestedPowerTransition";
807dd99e04bSP.K. Lee         const std::string propertyValue =
808dd99e04bSP.K. Lee             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
809002d39b4SEd Tanous         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
810c3b3c92aSVijay Khemka 
811c3b3c92aSVijay Khemka         /* Look for system reset chassis path */
8123544d2a7SEd Tanous         if ((std::ranges::find(chassisList, objectPath)) == chassisList.end())
813c3b3c92aSVijay Khemka         {
814c3b3c92aSVijay Khemka             /* We prefer to reset the full chassis_system, but if it doesn't
815c3b3c92aSVijay Khemka              * exist on some platforms, fall back to a host-only power reset
816c3b3c92aSVijay Khemka              */
817c3b3c92aSVijay Khemka             objectPath = "/xyz/openbmc_project/state/chassis0";
818c3b3c92aSVijay Khemka         }
819dd99e04bSP.K. Lee 
820d02aad39SEd Tanous         setDbusProperty(asyncResp, processName, objectPath, interfaceName,
821d02aad39SEd Tanous                         destProperty, "ResetType", propertyValue);
8227a1dbc48SGeorge Liu     });
823dd99e04bSP.K. Lee }
824dd99e04bSP.K. Lee 
825cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
826cf7eba09SNan Zhou     App& app, const crow::Request& req,
8277e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
828cf7eba09SNan Zhou     const std::string& /*chassisId*/)
829cf7eba09SNan Zhou {
8303ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
83145ca1b86SEd Tanous     {
83245ca1b86SEd Tanous         return;
83345ca1b86SEd Tanous     }
83462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
835dd99e04bSP.K. Lee 
836dd99e04bSP.K. Lee     std::string resetType;
837dd99e04bSP.K. Lee 
838cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
839dd99e04bSP.K. Lee     {
840dd99e04bSP.K. Lee         return;
841dd99e04bSP.K. Lee     }
842dd99e04bSP.K. Lee 
843dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
844dd99e04bSP.K. Lee     {
84562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
846002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
847002d39b4SEd Tanous                                               "ResetType");
848dd99e04bSP.K. Lee 
849dd99e04bSP.K. Lee         return;
850dd99e04bSP.K. Lee     }
851dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
852dd99e04bSP.K. Lee }
8531cb1a9e6SAppaRao Puli 
8541cb1a9e6SAppaRao Puli /**
855cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
856cf7eba09SNan Zhou  * action.
857cf7eba09SNan Zhou  * Function handles POST method request.
858cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8591cb1a9e6SAppaRao Puli  */
860cf7eba09SNan Zhou 
861cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8621cb1a9e6SAppaRao Puli {
863cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
864cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
865cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
866cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
867cf7eba09SNan Zhou }
868cf7eba09SNan Zhou 
869cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
870cf7eba09SNan Zhou     App& app, const crow::Request& req,
8717e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
872cf7eba09SNan Zhou     const std::string& chassisId)
873cf7eba09SNan Zhou {
8743ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
8751cb1a9e6SAppaRao Puli     {
87645ca1b86SEd Tanous         return;
87745ca1b86SEd Tanous     }
878cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
879ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
880ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
8811476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
8821476687dSEd Tanous 
8831476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
8845b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
8855b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
8865b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
8875b9e95a1SNan Zhou     parameter["Required"] = true;
8885b9e95a1SNan Zhou     parameter["DataType"] = "String";
8891476687dSEd Tanous     nlohmann::json::array_t allowed;
890ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
8915b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
892ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
8935b9e95a1SNan Zhou 
8941476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
895cf7eba09SNan Zhou }
896cf7eba09SNan Zhou 
897cf7eba09SNan Zhou /**
898cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
899cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
900cf7eba09SNan Zhou  */
901cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
902cf7eba09SNan Zhou {
903cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
904cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
905cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
906cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9071cb1a9e6SAppaRao Puli }
9081cb1a9e6SAppaRao Puli 
909e37f8451SRapkiewicz, Pawel } // namespace redfish
910