xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 89144a3a2f411d66727858d677cbd4b7aa8d14ba)
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         {
155*89144a3aSEd 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;
4057164bc62SChau Ly #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
4067164bc62SChau Ly     asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4077164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4087164bc62SChau Ly     // Power object
4097164bc62SChau Ly     asyncResp->res.jsonValue["Power"]["@odata.id"] =
4107164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
4117164bc62SChau Ly #endif
4127164bc62SChau Ly #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
4137164bc62SChau Ly     asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4147164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4157164bc62SChau Ly                             chassisId);
4167164bc62SChau Ly     asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
4177164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", chassisId);
4187164bc62SChau Ly     asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4197164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4207164bc62SChau Ly                             chassisId);
4217164bc62SChau Ly #endif
4227164bc62SChau Ly     // SensorCollection
4237164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4247164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
4257164bc62SChau Ly     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
4267164bc62SChau Ly 
4277164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4287164bc62SChau Ly     nlohmann::json::object_t system;
4297164bc62SChau Ly     system["@odata.id"] = "/redfish/v1/Systems/system";
4307164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4317164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4327164bc62SChau Ly         std::move(computerSystems);
4337164bc62SChau Ly 
4347164bc62SChau Ly     nlohmann::json::array_t managedBy;
4357164bc62SChau Ly     nlohmann::json::object_t manager;
4367164bc62SChau Ly     manager["@odata.id"] = "/redfish/v1/Managers/bmc";
4377164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4387164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4397164bc62SChau Ly     getChassisState(asyncResp);
4407164bc62SChau Ly     getStorageLink(asyncResp, path);
4417164bc62SChau Ly }
4427164bc62SChau Ly 
4437164bc62SChau Ly inline void handleChassisGetSubTree(
4447164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4457164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
4467164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
4477164bc62SChau Ly {
44862d5e2e4SEd Tanous     if (ec)
4491abe55efSEd Tanous     {
45062598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
451f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
452daf36e2eSEd Tanous         return;
453daf36e2eSEd Tanous     }
454daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
455cf7eba09SNan Zhou     for (const std::pair<
456cf7eba09SNan Zhou              std::string,
457cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
4581214b7e7SGunnar Mills              object : subtree)
4591abe55efSEd Tanous     {
460daf36e2eSEd Tanous         const std::string& path = object.first;
461cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
4621214b7e7SGunnar Mills             connectionNames = object.second;
4637e860f15SJohn Edward Broadbent 
464997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
465997093ebSGeorge Liu         if (objPath.filename() != chassisId)
4661abe55efSEd Tanous         {
467daf36e2eSEd Tanous             continue;
468daf36e2eSEd Tanous         }
46926f03899SShawn McCarney 
470a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
471a5617496SJie Yang 
47226f6976fSEd Tanous         if (connectionNames.empty())
4731abe55efSEd Tanous         {
47462598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
475e0d918bcSEd Tanous             continue;
476daf36e2eSEd Tanous         }
477e0d918bcSEd Tanous 
4787164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
47949c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
480ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
48149c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
48249c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
483cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
4847164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
4857164bc62SChau Ly                                 chassisId);
4861476687dSEd Tanous         asyncResp->res
487cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
488ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
489ef4c65b7SEd Tanous                                 chassisId);
4906c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
4916c3e9451SGeorge Liu             path + "/drive",
4927164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
4936c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
49492903bd4SJohn Edward Broadbent             if (ec3 || resp.empty())
49592903bd4SJohn Edward Broadbent             {
49692903bd4SJohn Edward Broadbent                 return; // no drives = no failures
49792903bd4SJohn Edward Broadbent             }
49892903bd4SJohn Edward Broadbent 
49992903bd4SJohn Edward Broadbent             nlohmann::json reference;
5007164bc62SChau Ly             reference["@odata.id"] =
5017164bc62SChau Ly                 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
50292903bd4SJohn Edward Broadbent             asyncResp->res.jsonValue["Drives"] = std::move(reference);
50392903bd4SJohn Edward Broadbent         });
50492903bd4SJohn Edward Broadbent 
505002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
5061c8fba97SJames Feist 
5077164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
508e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
509e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
5101c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5110fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5121c8fba97SJames Feist 
513476b9cc5STejas Patil         const std::string assetTagInterface =
5140fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
515523d4868SLogananth Sundararaj         const std::string replaceableInterface =
516523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
517b4d593f1SCarson Labrado         const std::string revisionInterface =
518b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
519523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
520523d4868SLogananth Sundararaj         {
521523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
522476b9cc5STejas Patil             {
5231e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
524002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
525002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
5267164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5271e1e598dSJonathan Doman                                            const std::string& property) {
5288a592810SEd Tanous                     if (ec2)
529476b9cc5STejas Patil                     {
5307164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBus response error for AssetTag: {}",
5317164bc62SChau Ly                                          ec2);
532476b9cc5STejas Patil                         messages::internalError(asyncResp->res);
533476b9cc5STejas Patil                         return;
534476b9cc5STejas Patil                     }
535002d39b4SEd Tanous                     asyncResp->res.jsonValue["AssetTag"] = property;
5361e1e598dSJonathan Doman                 });
537476b9cc5STejas Patil             }
538523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
539523d4868SLogananth Sundararaj             {
540523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
541523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
542523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
5437164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
544523d4868SLogananth Sundararaj                                            const bool property) {
545523d4868SLogananth Sundararaj                     if (ec2)
546523d4868SLogananth Sundararaj                     {
54762598e31SEd Tanous                         BMCWEB_LOG_ERROR(
5487164bc62SChau Ly                             "DBus response error for HotPluggable: {}", ec2);
549523d4868SLogananth Sundararaj                         messages::internalError(asyncResp->res);
550523d4868SLogananth Sundararaj                         return;
551523d4868SLogananth Sundararaj                     }
552523d4868SLogananth Sundararaj                     asyncResp->res.jsonValue["HotPluggable"] = property;
553523d4868SLogananth Sundararaj                 });
554523d4868SLogananth Sundararaj             }
555b4d593f1SCarson Labrado             else if (interface == revisionInterface)
556b4d593f1SCarson Labrado             {
557b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
558b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
559b4d593f1SCarson Labrado                     revisionInterface, "Version",
560b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
561b4d593f1SCarson Labrado                                            const std::string& property) {
562b4d593f1SCarson Labrado                     if (ec2)
563b4d593f1SCarson Labrado                     {
564b4d593f1SCarson Labrado                         BMCWEB_LOG_ERROR("DBus response error for Version: {}",
565b4d593f1SCarson Labrado                                          ec2);
566b4d593f1SCarson Labrado                         messages::internalError(asyncResp->res);
567b4d593f1SCarson Labrado                         return;
568b4d593f1SCarson Labrado                     }
569b4d593f1SCarson Labrado                     asyncResp->res.jsonValue["Version"] = property;
570b4d593f1SCarson Labrado                 });
571b4d593f1SCarson Labrado             }
572523d4868SLogananth Sundararaj         }
573476b9cc5STejas Patil 
5741c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
5751c8fba97SJames Feist         {
5767164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
5771c8fba97SJames Feist             {
5781c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
57959a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
5801c8fba97SJames Feist                 break;
5811c8fba97SJames Feist             }
5821c8fba97SJames Feist         }
5831c8fba97SJames Feist 
58486d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
58586d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
58686d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
5877164bc62SChau Ly             [asyncResp, chassisId,
5887164bc62SChau Ly              path](const boost::system::error_code&,
589cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
5907164bc62SChau Ly             handleDecoratorAssetProperties(asyncResp, chassisId, path,
5917164bc62SChau Ly                                            propertiesList);
59286d89ed7SKrzysztof Grobelny         });
5932c37b4b0SSharad Yadav 
594308f70c7SWilly Tu         for (const auto& interface : interfaces2)
5952c37b4b0SSharad Yadav         {
596308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
5972c37b4b0SSharad Yadav             {
598308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
5992c37b4b0SSharad Yadav             }
600cf7eba09SNan Zhou             else if (interface ==
6010fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6022c37b4b0SSharad Yadav             {
603002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6042c37b4b0SSharad Yadav             }
6052c37b4b0SSharad Yadav         }
6062c37b4b0SSharad Yadav 
607daf36e2eSEd Tanous         return;
608daf36e2eSEd Tanous     }
609e0d918bcSEd Tanous 
610daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
611d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6127164bc62SChau Ly }
613c181942fSQiang XU 
6147164bc62SChau Ly inline void
6157164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
6167164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6177164bc62SChau Ly                      const std::string& chassisId)
6187164bc62SChau Ly {
6197164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6207164bc62SChau Ly     {
6217164bc62SChau Ly         return;
6227164bc62SChau Ly     }
6237164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
6247164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
6257164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
6267164bc62SChau Ly 
6277164bc62SChau Ly     dbus::utility::getSubTree(
6287164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
6297164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6307164bc62SChau Ly 
6317164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6327164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6337164bc62SChau Ly 
6347164bc62SChau Ly     dbus::utility::getSubTree(
6357164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
6367164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
637cf7eba09SNan Zhou }
6381c8fba97SJames Feist 
639cf7eba09SNan Zhou inline void
640cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
6417e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
642cf7eba09SNan Zhou                        const std::string& param)
643cf7eba09SNan Zhou {
6443ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
64545ca1b86SEd Tanous     {
64645ca1b86SEd Tanous         return;
64745ca1b86SEd Tanous     }
6489f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
6491c8fba97SJames Feist     std::optional<std::string> indicatorLed;
6501c8fba97SJames Feist 
6517e860f15SJohn Edward Broadbent     if (param.empty())
6521c8fba97SJames Feist     {
6531c8fba97SJames Feist         return;
6541c8fba97SJames Feist     }
6551c8fba97SJames Feist 
65615ed6780SWilly Tu     if (!json_util::readJsonPatch(
6577e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
6587e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
6591c8fba97SJames Feist     {
6601c8fba97SJames Feist         return;
6611c8fba97SJames Feist     }
6621c8fba97SJames Feist 
6639f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6649f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6651c8fba97SJames Feist     {
6661c8fba97SJames Feist         return; // delete this when we support more patch properties
6671c8fba97SJames Feist     }
668d6aa0093SGunnar Mills     if (indicatorLed)
669d6aa0093SGunnar Mills     {
6707e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6717e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6720fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
673d6aa0093SGunnar Mills     }
6741c8fba97SJames Feist 
675e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
6761c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
6771c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
6781c8fba97SJames Feist 
6797e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
6801c8fba97SJames Feist 
681e99073f5SGeorge Liu     dbus::utility::getSubTree(
682e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
683cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
6845e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
685b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
6861c8fba97SJames Feist         if (ec)
6871c8fba97SJames Feist         {
68862598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
6891c8fba97SJames Feist             messages::internalError(asyncResp->res);
6901c8fba97SJames Feist             return;
6911c8fba97SJames Feist         }
6921c8fba97SJames Feist 
6931c8fba97SJames Feist         // Iterate over all retrieved ObjectPaths.
694cf7eba09SNan Zhou         for (const std::pair<
695cf7eba09SNan Zhou                  std::string,
696cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
6971214b7e7SGunnar Mills                  object : subtree)
6981c8fba97SJames Feist         {
6991c8fba97SJames Feist             const std::string& path = object.first;
700cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
7011214b7e7SGunnar Mills                 connectionNames = object.second;
7021c8fba97SJames Feist 
703997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
704997093ebSGeorge Liu             if (objPath.filename() != chassisId)
7051c8fba97SJames Feist             {
7061c8fba97SJames Feist                 continue;
7071c8fba97SJames Feist             }
7081c8fba97SJames Feist 
70926f6976fSEd Tanous             if (connectionNames.empty())
7101c8fba97SJames Feist             {
71162598e31SEd Tanous                 BMCWEB_LOG_ERROR("Got 0 Connection names");
7121c8fba97SJames Feist                 continue;
7131c8fba97SJames Feist             }
7141c8fba97SJames Feist 
71523a21a1cSEd Tanous             const std::vector<std::string>& interfaces3 =
7161c8fba97SJames Feist                 connectionNames[0].second;
7171c8fba97SJames Feist 
718e5ae9c1cSGeorge Liu             const std::array<const char*, 3> hasIndicatorLed = {
719e5ae9c1cSGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Chassis",
7201c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
7210fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7221c8fba97SJames Feist             bool indicatorChassis = false;
7231c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
7241c8fba97SJames Feist             {
7253544d2a7SEd Tanous                 if (std::ranges::find(interfaces3, interface) !=
7263544d2a7SEd Tanous                     interfaces3.end())
7271c8fba97SJames Feist                 {
7281c8fba97SJames Feist                     indicatorChassis = true;
7291c8fba97SJames Feist                     break;
7301c8fba97SJames Feist                 }
7311c8fba97SJames Feist             }
7329f8bfa7cSGunnar Mills             if (locationIndicatorActive)
7339f8bfa7cSGunnar Mills             {
7349f8bfa7cSGunnar Mills                 if (indicatorChassis)
7359f8bfa7cSGunnar Mills                 {
73659a17e4fSGeorge Liu                     setSystemLocationIndicatorActive(asyncResp,
737002d39b4SEd Tanous                                                      *locationIndicatorActive);
7389f8bfa7cSGunnar Mills                 }
7399f8bfa7cSGunnar Mills                 else
7409f8bfa7cSGunnar Mills                 {
741002d39b4SEd Tanous                     messages::propertyUnknown(asyncResp->res,
742002d39b4SEd Tanous                                               "LocationIndicatorActive");
7439f8bfa7cSGunnar Mills                 }
7449f8bfa7cSGunnar Mills             }
7459f8bfa7cSGunnar Mills             if (indicatorLed)
7469f8bfa7cSGunnar Mills             {
7471c8fba97SJames Feist                 if (indicatorChassis)
7481c8fba97SJames Feist                 {
749f23b7296SEd Tanous                     setIndicatorLedState(asyncResp, *indicatorLed);
7501c8fba97SJames Feist                 }
7511c8fba97SJames Feist                 else
7521c8fba97SJames Feist                 {
753cf7eba09SNan Zhou                     messages::propertyUnknown(asyncResp->res, "IndicatorLED");
7541c8fba97SJames Feist                 }
7551c8fba97SJames Feist             }
7561c8fba97SJames Feist             return;
7571c8fba97SJames Feist         }
7581c8fba97SJames Feist 
759d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
760e99073f5SGeorge Liu     });
761cf7eba09SNan Zhou }
762cf7eba09SNan Zhou 
763cf7eba09SNan Zhou /**
764cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
765cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
766cf7eba09SNan Zhou  */
767cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
768cf7eba09SNan Zhou {
769cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
770cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
771cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
772cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
773cf7eba09SNan Zhou 
774cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
775cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
776cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
777cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
7781c8fba97SJames Feist }
779dd99e04bSP.K. Lee 
7808d1b46d7Szhanghch05 inline void
7818d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
782dd99e04bSP.K. Lee {
7837a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
784c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
785c3b3c92aSVijay Khemka 
786c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
7877a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
7887a1dbc48SGeorge Liu         "/", 0, interfaces,
789b9d36b47SEd Tanous         [asyncResp](
7907a1dbc48SGeorge Liu             const boost::system::error_code& ec,
791b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
792c3b3c92aSVijay Khemka         if (ec)
793c3b3c92aSVijay Khemka         {
79462598e31SEd Tanous             BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
795c3b3c92aSVijay Khemka             messages::internalError(asyncResp->res);
796c3b3c92aSVijay Khemka             return;
797c3b3c92aSVijay Khemka         }
798c3b3c92aSVijay Khemka 
799dd99e04bSP.K. Lee         const char* processName = "xyz.openbmc_project.State.Chassis";
800dd99e04bSP.K. Lee         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
801dd99e04bSP.K. Lee         const char* destProperty = "RequestedPowerTransition";
802dd99e04bSP.K. Lee         const std::string propertyValue =
803dd99e04bSP.K. Lee             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
804002d39b4SEd Tanous         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
805c3b3c92aSVijay Khemka 
806c3b3c92aSVijay Khemka         /* Look for system reset chassis path */
8073544d2a7SEd Tanous         if ((std::ranges::find(chassisList, objectPath)) == chassisList.end())
808c3b3c92aSVijay Khemka         {
809c3b3c92aSVijay Khemka             /* We prefer to reset the full chassis_system, but if it doesn't
810c3b3c92aSVijay Khemka              * exist on some platforms, fall back to a host-only power reset
811c3b3c92aSVijay Khemka              */
812c3b3c92aSVijay Khemka             objectPath = "/xyz/openbmc_project/state/chassis0";
813c3b3c92aSVijay Khemka         }
814dd99e04bSP.K. Lee 
815d02aad39SEd Tanous         setDbusProperty(asyncResp, processName, objectPath, interfaceName,
816d02aad39SEd Tanous                         destProperty, "ResetType", propertyValue);
8177a1dbc48SGeorge Liu     });
818dd99e04bSP.K. Lee }
819dd99e04bSP.K. Lee 
820cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
821cf7eba09SNan Zhou     App& app, const crow::Request& req,
8227e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
823cf7eba09SNan Zhou     const std::string& /*chassisId*/)
824cf7eba09SNan Zhou {
8253ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
82645ca1b86SEd Tanous     {
82745ca1b86SEd Tanous         return;
82845ca1b86SEd Tanous     }
82962598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
830dd99e04bSP.K. Lee 
831dd99e04bSP.K. Lee     std::string resetType;
832dd99e04bSP.K. Lee 
833cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
834dd99e04bSP.K. Lee     {
835dd99e04bSP.K. Lee         return;
836dd99e04bSP.K. Lee     }
837dd99e04bSP.K. Lee 
838dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
839dd99e04bSP.K. Lee     {
84062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
841002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
842002d39b4SEd Tanous                                               "ResetType");
843dd99e04bSP.K. Lee 
844dd99e04bSP.K. Lee         return;
845dd99e04bSP.K. Lee     }
846dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
847dd99e04bSP.K. Lee }
8481cb1a9e6SAppaRao Puli 
8491cb1a9e6SAppaRao Puli /**
850cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
851cf7eba09SNan Zhou  * action.
852cf7eba09SNan Zhou  * Function handles POST method request.
853cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8541cb1a9e6SAppaRao Puli  */
855cf7eba09SNan Zhou 
856cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8571cb1a9e6SAppaRao Puli {
858cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
859cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
860cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
861cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
862cf7eba09SNan Zhou }
863cf7eba09SNan Zhou 
864cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
865cf7eba09SNan Zhou     App& app, const crow::Request& req,
8667e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
867cf7eba09SNan Zhou     const std::string& chassisId)
868cf7eba09SNan Zhou {
8693ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
8701cb1a9e6SAppaRao Puli     {
87145ca1b86SEd Tanous         return;
87245ca1b86SEd Tanous     }
873cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
874ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
875ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
8761476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
8771476687dSEd Tanous 
8781476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
8795b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
8805b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
8815b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
8825b9e95a1SNan Zhou     parameter["Required"] = true;
8835b9e95a1SNan Zhou     parameter["DataType"] = "String";
8841476687dSEd Tanous     nlohmann::json::array_t allowed;
885ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
8865b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
887ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
8885b9e95a1SNan Zhou 
8891476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
890cf7eba09SNan Zhou }
891cf7eba09SNan Zhou 
892cf7eba09SNan Zhou /**
893cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
894cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
895cf7eba09SNan Zhou  */
896cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
897cf7eba09SNan Zhou {
898cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
899cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
900cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
901cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9021cb1a9e6SAppaRao Puli }
9031cb1a9e6SAppaRao Puli 
904e37f8451SRapkiewicz, Pawel } // namespace redfish
905