xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision e93abac6d60c4b409ad72086dac153f23d793ac1)
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;
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  */
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  */
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 
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 
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,
208a5617496SJie Yang     const dbus::utility::MapperEndPoints& 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 
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,
247a5617496SJie Yang     const dbus::utility::MapperEndPoints& 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
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 
293a5617496SJie Yang     dbus::utility::getAssociationEndPoints(
294a5617496SJie Yang         chassisPath + "/contained_by",
295a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
296a5617496SJie Yang 
297a5617496SJie Yang     dbus::utility::getAssociationEndPoints(
298a5617496SJie Yang         chassisPath + "/containing",
299a5617496SJie Yang         std::bind_front(getChassisContains, asyncResp, chassisId));
300a5617496SJie Yang }
301a5617496SJie Yang 
302cf7eba09SNan Zhou /**
303cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
304cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
305cf7eba09SNan Zhou  */
306cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
307cf7eba09SNan Zhou {
308cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
309cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
310cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
311cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
31262d5e2e4SEd Tanous }
313e37f8451SRapkiewicz, Pawel 
314308f70c7SWilly Tu inline void
315308f70c7SWilly Tu     getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
316308f70c7SWilly Tu                            const std::string& connectionName,
317308f70c7SWilly Tu                            const std::string& path)
318308f70c7SWilly Tu {
3191e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3201e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3211e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3225e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3231e1e598dSJonathan Doman                     const std::string& property) {
324308f70c7SWilly Tu         if (ec)
325308f70c7SWilly Tu         {
32662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for Location");
327308f70c7SWilly Tu             messages::internalError(asyncResp->res);
328308f70c7SWilly Tu             return;
329308f70c7SWilly Tu         }
330308f70c7SWilly Tu 
331002d39b4SEd Tanous         asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3321e1e598dSJonathan Doman             property;
3331e1e598dSJonathan Doman     });
334308f70c7SWilly Tu }
335308f70c7SWilly Tu 
336308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
337308f70c7SWilly Tu                            const std::string& connectionName,
338308f70c7SWilly Tu                            const std::string& path)
339308f70c7SWilly Tu {
3401e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3411e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3421e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
3435e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3441e1e598dSJonathan Doman                     const std::string& chassisUUID) {
345308f70c7SWilly Tu         if (ec)
346308f70c7SWilly Tu         {
34762598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for UUID");
348308f70c7SWilly Tu             messages::internalError(asyncResp->res);
349308f70c7SWilly Tu             return;
350308f70c7SWilly Tu         }
3511e1e598dSJonathan Doman         asyncResp->res.jsonValue["UUID"] = chassisUUID;
3521e1e598dSJonathan Doman     });
353308f70c7SWilly Tu }
354308f70c7SWilly Tu 
3557164bc62SChau Ly inline void handleDecoratorAssetProperties(
35645ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3577164bc62SChau Ly     const std::string& chassisId, const std::string& path,
3587164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
359cf7eba09SNan Zhou {
3607164bc62SChau Ly     const std::string* partNumber = nullptr;
3617164bc62SChau Ly     const std::string* serialNumber = nullptr;
3627164bc62SChau Ly     const std::string* manufacturer = nullptr;
3637164bc62SChau Ly     const std::string* model = nullptr;
3647164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
3657164bc62SChau Ly 
3667164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
3677164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
3687164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
3697164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
3707164bc62SChau Ly 
3717164bc62SChau Ly     if (!success)
37245ca1b86SEd Tanous     {
3737164bc62SChau Ly         messages::internalError(asyncResp->res);
37445ca1b86SEd Tanous         return;
37545ca1b86SEd Tanous     }
376734bfe90SGunnar Mills 
3777164bc62SChau Ly     if (partNumber != nullptr)
3787164bc62SChau Ly     {
3797164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3807164bc62SChau Ly     }
3817164bc62SChau Ly 
3827164bc62SChau Ly     if (serialNumber != nullptr)
3837164bc62SChau Ly     {
3847164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3857164bc62SChau Ly     }
3867164bc62SChau Ly 
3877164bc62SChau Ly     if (manufacturer != nullptr)
3887164bc62SChau Ly     {
3897164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3907164bc62SChau Ly     }
3917164bc62SChau Ly 
3927164bc62SChau Ly     if (model != nullptr)
3937164bc62SChau Ly     {
3947164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
3957164bc62SChau Ly     }
3967164bc62SChau Ly 
3977164bc62SChau Ly     // SparePartNumber is optional on D-Bus
3987164bc62SChau Ly     // so skip if it is empty
3997164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
4007164bc62SChau Ly     {
4017164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4027164bc62SChau Ly     }
4037164bc62SChau Ly 
4047164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4057164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
40625b54dbaSEd Tanous 
40725b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
40825b54dbaSEd Tanous     {
4097164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4107164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4117164bc62SChau Ly         // Power object
4127164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4137164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
41425b54dbaSEd Tanous     }
41525b54dbaSEd Tanous 
41625b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
41725b54dbaSEd Tanous     {
4187164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4197164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4207164bc62SChau Ly                                 chassisId);
4217164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
42225b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
42325b54dbaSEd Tanous                                 chassisId);
4247164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4257164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4267164bc62SChau Ly                                 chassisId);
42725b54dbaSEd Tanous     }
4287164bc62SChau Ly     // SensorCollection
4297164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4307164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
4317164bc62SChau Ly     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
4327164bc62SChau Ly 
4337164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4347164bc62SChau Ly     nlohmann::json::object_t system;
435253f11b8SEd Tanous     system["@odata.id"] = std::format("/redfish/v1/Systems/{}",
436253f11b8SEd Tanous                                       BMCWEB_REDFISH_SYSTEM_URI_NAME);
4377164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4387164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4397164bc62SChau Ly         std::move(computerSystems);
4407164bc62SChau Ly 
4417164bc62SChau Ly     nlohmann::json::array_t managedBy;
4427164bc62SChau Ly     nlohmann::json::object_t manager;
443253f11b8SEd Tanous     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
444253f11b8SEd Tanous                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
4457164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4467164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4477164bc62SChau Ly     getChassisState(asyncResp);
4487164bc62SChau Ly     getStorageLink(asyncResp, path);
4497164bc62SChau Ly }
4507164bc62SChau Ly 
4517164bc62SChau Ly inline void handleChassisGetSubTree(
4527164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4537164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
4547164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
4557164bc62SChau Ly {
45662d5e2e4SEd Tanous     if (ec)
4571abe55efSEd Tanous     {
45862598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
459f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
460daf36e2eSEd Tanous         return;
461daf36e2eSEd Tanous     }
462daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
463cf7eba09SNan Zhou     for (const std::pair<
464cf7eba09SNan Zhou              std::string,
465cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
4661214b7e7SGunnar Mills              object : subtree)
4671abe55efSEd Tanous     {
468daf36e2eSEd Tanous         const std::string& path = object.first;
469cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
4701214b7e7SGunnar Mills             connectionNames = object.second;
4717e860f15SJohn Edward Broadbent 
472997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
473997093ebSGeorge Liu         if (objPath.filename() != chassisId)
4741abe55efSEd Tanous         {
475daf36e2eSEd Tanous             continue;
476daf36e2eSEd Tanous         }
47726f03899SShawn McCarney 
478a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
479a5617496SJie Yang 
48026f6976fSEd Tanous         if (connectionNames.empty())
4811abe55efSEd Tanous         {
48262598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
483e0d918bcSEd Tanous             continue;
484daf36e2eSEd Tanous         }
485e0d918bcSEd Tanous 
4867164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
48749c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
488ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
48949c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
49049c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
491cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
4927164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
4937164bc62SChau Ly                                 chassisId);
4941476687dSEd Tanous         asyncResp->res
495cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
496ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
497ef4c65b7SEd Tanous                                 chassisId);
4986c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
4996c3e9451SGeorge Liu             path + "/drive",
5007164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
5016c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
50292903bd4SJohn Edward Broadbent             if (ec3 || resp.empty())
50392903bd4SJohn Edward Broadbent             {
50492903bd4SJohn Edward Broadbent                 return; // no drives = no failures
50592903bd4SJohn Edward Broadbent             }
50692903bd4SJohn Edward Broadbent 
50792903bd4SJohn Edward Broadbent             nlohmann::json reference;
5087164bc62SChau Ly             reference["@odata.id"] =
5097164bc62SChau Ly                 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
51092903bd4SJohn Edward Broadbent             asyncResp->res.jsonValue["Drives"] = std::move(reference);
51192903bd4SJohn Edward Broadbent         });
51292903bd4SJohn Edward Broadbent 
513002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
5141c8fba97SJames Feist 
5157164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
516e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
517e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
5181c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5190fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5201c8fba97SJames Feist 
521476b9cc5STejas Patil         const std::string assetTagInterface =
5220fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
523523d4868SLogananth Sundararaj         const std::string replaceableInterface =
524523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
525b4d593f1SCarson Labrado         const std::string revisionInterface =
526b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
527523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
528523d4868SLogananth Sundararaj         {
529523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
530476b9cc5STejas Patil             {
5311e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
532002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
533002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
5347164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5351e1e598dSJonathan Doman                                            const std::string& property) {
5368a592810SEd Tanous                     if (ec2)
537476b9cc5STejas Patil                     {
5387164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBus response error for AssetTag: {}",
5397164bc62SChau Ly                                          ec2);
540476b9cc5STejas Patil                         messages::internalError(asyncResp->res);
541476b9cc5STejas Patil                         return;
542476b9cc5STejas Patil                     }
543002d39b4SEd Tanous                     asyncResp->res.jsonValue["AssetTag"] = property;
5441e1e598dSJonathan Doman                 });
545476b9cc5STejas Patil             }
546523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
547523d4868SLogananth Sundararaj             {
548523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
549523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
550523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
5517164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
552523d4868SLogananth Sundararaj                                            const bool property) {
553523d4868SLogananth Sundararaj                     if (ec2)
554523d4868SLogananth Sundararaj                     {
55562598e31SEd Tanous                         BMCWEB_LOG_ERROR(
5567164bc62SChau Ly                             "DBus response error for HotPluggable: {}", ec2);
557523d4868SLogananth Sundararaj                         messages::internalError(asyncResp->res);
558523d4868SLogananth Sundararaj                         return;
559523d4868SLogananth Sundararaj                     }
560523d4868SLogananth Sundararaj                     asyncResp->res.jsonValue["HotPluggable"] = property;
561523d4868SLogananth Sundararaj                 });
562523d4868SLogananth Sundararaj             }
563b4d593f1SCarson Labrado             else if (interface == revisionInterface)
564b4d593f1SCarson Labrado             {
565b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
566b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
567b4d593f1SCarson Labrado                     revisionInterface, "Version",
568b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
569b4d593f1SCarson Labrado                                            const std::string& property) {
570b4d593f1SCarson Labrado                     if (ec2)
571b4d593f1SCarson Labrado                     {
572b4d593f1SCarson Labrado                         BMCWEB_LOG_ERROR("DBus response error for Version: {}",
573b4d593f1SCarson Labrado                                          ec2);
574b4d593f1SCarson Labrado                         messages::internalError(asyncResp->res);
575b4d593f1SCarson Labrado                         return;
576b4d593f1SCarson Labrado                     }
577b4d593f1SCarson Labrado                     asyncResp->res.jsonValue["Version"] = property;
578b4d593f1SCarson Labrado                 });
579b4d593f1SCarson Labrado             }
580523d4868SLogananth Sundararaj         }
581476b9cc5STejas Patil 
5821c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
5831c8fba97SJames Feist         {
5847164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
5851c8fba97SJames Feist             {
5861c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
58759a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
5881c8fba97SJames Feist                 break;
5891c8fba97SJames Feist             }
5901c8fba97SJames Feist         }
5911c8fba97SJames Feist 
59286d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
59386d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
59486d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
5957164bc62SChau Ly             [asyncResp, chassisId,
5967164bc62SChau Ly              path](const boost::system::error_code&,
597cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
5987164bc62SChau Ly             handleDecoratorAssetProperties(asyncResp, chassisId, path,
5997164bc62SChau Ly                                            propertiesList);
60086d89ed7SKrzysztof Grobelny         });
6012c37b4b0SSharad Yadav 
602308f70c7SWilly Tu         for (const auto& interface : interfaces2)
6032c37b4b0SSharad Yadav         {
604308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
6052c37b4b0SSharad Yadav             {
606308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
6072c37b4b0SSharad Yadav             }
608cf7eba09SNan Zhou             else if (interface ==
6090fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6102c37b4b0SSharad Yadav             {
611002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6122c37b4b0SSharad Yadav             }
6132c37b4b0SSharad Yadav         }
6142c37b4b0SSharad Yadav 
615daf36e2eSEd Tanous         return;
616daf36e2eSEd Tanous     }
617e0d918bcSEd Tanous 
618daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
619d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6207164bc62SChau Ly }
621c181942fSQiang XU 
6227164bc62SChau Ly inline void
6237164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
6247164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6257164bc62SChau Ly                      const std::string& chassisId)
6267164bc62SChau Ly {
6277164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6287164bc62SChau Ly     {
6297164bc62SChau Ly         return;
6307164bc62SChau Ly     }
6317164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
6327164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
6337164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
6347164bc62SChau Ly 
6357164bc62SChau Ly     dbus::utility::getSubTree(
6367164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
6377164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6387164bc62SChau Ly 
6397164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6407164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6417164bc62SChau Ly 
6427164bc62SChau Ly     dbus::utility::getSubTree(
6437164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
6447164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
645cf7eba09SNan Zhou }
6461c8fba97SJames Feist 
647cf7eba09SNan Zhou inline void
648cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
6497e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
650cf7eba09SNan Zhou                        const std::string& param)
651cf7eba09SNan Zhou {
6523ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65345ca1b86SEd Tanous     {
65445ca1b86SEd Tanous         return;
65545ca1b86SEd Tanous     }
6569f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
6571c8fba97SJames Feist     std::optional<std::string> indicatorLed;
6581c8fba97SJames Feist 
6597e860f15SJohn Edward Broadbent     if (param.empty())
6601c8fba97SJames Feist     {
6611c8fba97SJames Feist         return;
6621c8fba97SJames Feist     }
6631c8fba97SJames Feist 
66415ed6780SWilly Tu     if (!json_util::readJsonPatch(
6657e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
6667e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
6671c8fba97SJames Feist     {
6681c8fba97SJames Feist         return;
6691c8fba97SJames Feist     }
6701c8fba97SJames Feist 
6719f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6729f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6731c8fba97SJames Feist     {
6741c8fba97SJames Feist         return; // delete this when we support more patch properties
6751c8fba97SJames Feist     }
676d6aa0093SGunnar Mills     if (indicatorLed)
677d6aa0093SGunnar Mills     {
6787e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6797e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6800fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
681d6aa0093SGunnar Mills     }
6821c8fba97SJames Feist 
683e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
6841c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
6851c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
6861c8fba97SJames Feist 
6877e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
6881c8fba97SJames Feist 
689e99073f5SGeorge Liu     dbus::utility::getSubTree(
690e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
691cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
6925e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
693b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
6941c8fba97SJames Feist         if (ec)
6951c8fba97SJames Feist         {
69662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
6971c8fba97SJames Feist             messages::internalError(asyncResp->res);
6981c8fba97SJames Feist             return;
6991c8fba97SJames Feist         }
7001c8fba97SJames Feist 
7011c8fba97SJames Feist         // Iterate over all retrieved ObjectPaths.
702cf7eba09SNan Zhou         for (const std::pair<
703cf7eba09SNan Zhou                  std::string,
704cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
7051214b7e7SGunnar Mills                  object : subtree)
7061c8fba97SJames Feist         {
7071c8fba97SJames Feist             const std::string& path = object.first;
708cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
7091214b7e7SGunnar Mills                 connectionNames = object.second;
7101c8fba97SJames Feist 
711997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
712997093ebSGeorge Liu             if (objPath.filename() != chassisId)
7131c8fba97SJames Feist             {
7141c8fba97SJames Feist                 continue;
7151c8fba97SJames Feist             }
7161c8fba97SJames Feist 
71726f6976fSEd Tanous             if (connectionNames.empty())
7181c8fba97SJames Feist             {
71962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Got 0 Connection names");
7201c8fba97SJames Feist                 continue;
7211c8fba97SJames Feist             }
7221c8fba97SJames Feist 
72323a21a1cSEd Tanous             const std::vector<std::string>& interfaces3 =
7241c8fba97SJames Feist                 connectionNames[0].second;
7251c8fba97SJames Feist 
726e5ae9c1cSGeorge Liu             const std::array<const char*, 3> hasIndicatorLed = {
727e5ae9c1cSGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Chassis",
7281c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
7290fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7301c8fba97SJames Feist             bool indicatorChassis = false;
7311c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
7321c8fba97SJames Feist             {
7333544d2a7SEd Tanous                 if (std::ranges::find(interfaces3, interface) !=
7343544d2a7SEd Tanous                     interfaces3.end())
7351c8fba97SJames Feist                 {
7361c8fba97SJames Feist                     indicatorChassis = true;
7371c8fba97SJames Feist                     break;
7381c8fba97SJames Feist                 }
7391c8fba97SJames Feist             }
7409f8bfa7cSGunnar Mills             if (locationIndicatorActive)
7419f8bfa7cSGunnar Mills             {
7429f8bfa7cSGunnar Mills                 if (indicatorChassis)
7439f8bfa7cSGunnar Mills                 {
74459a17e4fSGeorge Liu                     setSystemLocationIndicatorActive(asyncResp,
745002d39b4SEd Tanous                                                      *locationIndicatorActive);
7469f8bfa7cSGunnar Mills                 }
7479f8bfa7cSGunnar Mills                 else
7489f8bfa7cSGunnar Mills                 {
749002d39b4SEd Tanous                     messages::propertyUnknown(asyncResp->res,
750002d39b4SEd Tanous                                               "LocationIndicatorActive");
7519f8bfa7cSGunnar Mills                 }
7529f8bfa7cSGunnar Mills             }
7539f8bfa7cSGunnar Mills             if (indicatorLed)
7549f8bfa7cSGunnar Mills             {
7551c8fba97SJames Feist                 if (indicatorChassis)
7561c8fba97SJames Feist                 {
757f23b7296SEd Tanous                     setIndicatorLedState(asyncResp, *indicatorLed);
7581c8fba97SJames Feist                 }
7591c8fba97SJames Feist                 else
7601c8fba97SJames Feist                 {
761cf7eba09SNan Zhou                     messages::propertyUnknown(asyncResp->res, "IndicatorLED");
7621c8fba97SJames Feist                 }
7631c8fba97SJames Feist             }
7641c8fba97SJames Feist             return;
7651c8fba97SJames Feist         }
7661c8fba97SJames Feist 
767d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
768e99073f5SGeorge Liu     });
769cf7eba09SNan Zhou }
770cf7eba09SNan Zhou 
771cf7eba09SNan Zhou /**
772cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
773cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
774cf7eba09SNan Zhou  */
775cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
776cf7eba09SNan Zhou {
777cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
778cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
779cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
780cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
781cf7eba09SNan Zhou 
782cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
783cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
784cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
785cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
7861c8fba97SJames Feist }
787dd99e04bSP.K. Lee 
7888d1b46d7Szhanghch05 inline void
7898d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
790dd99e04bSP.K. Lee {
7917a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
792c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
793c3b3c92aSVijay Khemka 
794c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
7957a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
7967a1dbc48SGeorge Liu         "/", 0, interfaces,
797b9d36b47SEd Tanous         [asyncResp](
7987a1dbc48SGeorge Liu             const boost::system::error_code& ec,
799b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
800c3b3c92aSVijay Khemka         if (ec)
801c3b3c92aSVijay Khemka         {
80262598e31SEd Tanous             BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
803c3b3c92aSVijay Khemka             messages::internalError(asyncResp->res);
804c3b3c92aSVijay Khemka             return;
805c3b3c92aSVijay Khemka         }
806c3b3c92aSVijay Khemka 
807dd99e04bSP.K. Lee         const char* processName = "xyz.openbmc_project.State.Chassis";
808dd99e04bSP.K. Lee         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
809dd99e04bSP.K. Lee         const char* destProperty = "RequestedPowerTransition";
810dd99e04bSP.K. Lee         const std::string propertyValue =
811dd99e04bSP.K. Lee             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
812002d39b4SEd Tanous         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
813c3b3c92aSVijay Khemka 
814c3b3c92aSVijay Khemka         /* Look for system reset chassis path */
8153544d2a7SEd Tanous         if ((std::ranges::find(chassisList, objectPath)) == chassisList.end())
816c3b3c92aSVijay Khemka         {
817c3b3c92aSVijay Khemka             /* We prefer to reset the full chassis_system, but if it doesn't
818c3b3c92aSVijay Khemka              * exist on some platforms, fall back to a host-only power reset
819c3b3c92aSVijay Khemka              */
820c3b3c92aSVijay Khemka             objectPath = "/xyz/openbmc_project/state/chassis0";
821c3b3c92aSVijay Khemka         }
822dd99e04bSP.K. Lee 
823*e93abac6SGinu George         setDbusProperty(asyncResp, "ResetType", processName, objectPath,
824*e93abac6SGinu George                         interfaceName, destProperty, propertyValue);
8257a1dbc48SGeorge Liu     });
826dd99e04bSP.K. Lee }
827dd99e04bSP.K. Lee 
828cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
829cf7eba09SNan Zhou     App& app, const crow::Request& req,
8307e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
831cf7eba09SNan Zhou     const std::string& /*chassisId*/)
832cf7eba09SNan Zhou {
8333ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
83445ca1b86SEd Tanous     {
83545ca1b86SEd Tanous         return;
83645ca1b86SEd Tanous     }
83762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
838dd99e04bSP.K. Lee 
839dd99e04bSP.K. Lee     std::string resetType;
840dd99e04bSP.K. Lee 
841cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
842dd99e04bSP.K. Lee     {
843dd99e04bSP.K. Lee         return;
844dd99e04bSP.K. Lee     }
845dd99e04bSP.K. Lee 
846dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
847dd99e04bSP.K. Lee     {
84862598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
849002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
850002d39b4SEd Tanous                                               "ResetType");
851dd99e04bSP.K. Lee 
852dd99e04bSP.K. Lee         return;
853dd99e04bSP.K. Lee     }
854dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
855dd99e04bSP.K. Lee }
8561cb1a9e6SAppaRao Puli 
8571cb1a9e6SAppaRao Puli /**
858cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
859cf7eba09SNan Zhou  * action.
860cf7eba09SNan Zhou  * Function handles POST method request.
861cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8621cb1a9e6SAppaRao Puli  */
863cf7eba09SNan Zhou 
864cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8651cb1a9e6SAppaRao Puli {
866cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
867cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
868cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
869cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
870cf7eba09SNan Zhou }
871cf7eba09SNan Zhou 
872cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
873cf7eba09SNan Zhou     App& app, const crow::Request& req,
8747e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
875cf7eba09SNan Zhou     const std::string& chassisId)
876cf7eba09SNan Zhou {
8773ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
8781cb1a9e6SAppaRao Puli     {
87945ca1b86SEd Tanous         return;
88045ca1b86SEd Tanous     }
881cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
882ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
883ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
8841476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
8851476687dSEd Tanous 
8861476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
8875b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
8885b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
8895b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
8905b9e95a1SNan Zhou     parameter["Required"] = true;
8915b9e95a1SNan Zhou     parameter["DataType"] = "String";
8921476687dSEd Tanous     nlohmann::json::array_t allowed;
893ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
8945b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
895ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
8965b9e95a1SNan Zhou 
8971476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
898cf7eba09SNan Zhou }
899cf7eba09SNan Zhou 
900cf7eba09SNan Zhou /**
901cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
902cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
903cf7eba09SNan Zhou  */
904cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
905cf7eba09SNan Zhou {
906cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
907cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
908cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
909cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9101cb1a9e6SAppaRao Puli }
9111cb1a9e6SAppaRao Puli 
912e37f8451SRapkiewicz, Pawel } // namespace redfish
913