xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision f7e62c142ced153e9400b519bdd66062dd6bbf0e)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4e37f8451SRapkiewicz, Pawel #pragma once
5e37f8451SRapkiewicz, Pawel 
6d7857201SEd Tanous #include "bmcweb_config.h"
7d7857201SEd Tanous 
83ccb3adbSEd Tanous #include "app.hpp"
9d7857201SEd Tanous #include "async_resp.hpp"
10d7857201SEd Tanous #include "dbus_singleton.hpp"
117a1dbc48SGeorge Liu #include "dbus_utility.hpp"
12d7857201SEd Tanous #include "error_messages.hpp"
13539d8c6bSEd Tanous #include "generated/enums/action_info.hpp"
14539d8c6bSEd Tanous #include "generated/enums/chassis.hpp"
15539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
16d7857201SEd Tanous #include "http_request.hpp"
171c8fba97SJames Feist #include "led.hpp"
18d7857201SEd Tanous #include "logging.hpp"
193ccb3adbSEd Tanous #include "query.hpp"
203ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
21*f7e62c14SMyung Bae #include "utils/asset_utils.hpp"
223f95a277SMyung Bae #include "utils/chassis_utils.hpp"
233ccb3adbSEd Tanous #include "utils/collection.hpp"
243ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
25cf7eba09SNan Zhou #include "utils/json_utils.hpp"
261abe55efSEd Tanous 
27d7857201SEd Tanous #include <asm-generic/errno.h>
28d7857201SEd Tanous 
29d7857201SEd Tanous #include <boost/beast/http/field.hpp>
30d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
31e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
32ef4c65b7SEd Tanous #include <boost/url/format.hpp>
33d7857201SEd Tanous #include <boost/url/url.hpp>
34d7857201SEd Tanous #include <nlohmann/json.hpp>
35d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
3686d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
371214b7e7SGunnar Mills 
38d7857201SEd Tanous #include <algorithm>
397a1dbc48SGeorge Liu #include <array>
40d7857201SEd Tanous #include <format>
41d7857201SEd Tanous #include <functional>
422952f648SJoseph-Jonathan Salzano #include <memory>
43d7857201SEd Tanous #include <optional>
443544d2a7SEd Tanous #include <ranges>
45d7857201SEd Tanous #include <string>
467a1dbc48SGeorge Liu #include <string_view>
47d7857201SEd Tanous #include <utility>
48d7857201SEd Tanous #include <vector>
497a1dbc48SGeorge Liu 
501abe55efSEd Tanous namespace redfish
511abe55efSEd Tanous {
52e37f8451SRapkiewicz, Pawel 
53504af5a0SPatrick Williams inline chassis::ChassisType translateChassisTypeToRedfish(
54504af5a0SPatrick Williams     const std::string_view& chassisType)
552952f648SJoseph-Jonathan Salzano {
562952f648SJoseph-Jonathan Salzano     if (chassisType ==
572952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade")
582952f648SJoseph-Jonathan Salzano     {
592952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Blade;
602952f648SJoseph-Jonathan Salzano     }
612952f648SJoseph-Jonathan Salzano     if (chassisType ==
622952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component")
632952f648SJoseph-Jonathan Salzano     {
642952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Component;
652952f648SJoseph-Jonathan Salzano     }
662952f648SJoseph-Jonathan Salzano     if (chassisType ==
672952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure")
682952f648SJoseph-Jonathan Salzano     {
692952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Enclosure;
702952f648SJoseph-Jonathan Salzano     }
712952f648SJoseph-Jonathan Salzano     if (chassisType ==
722952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module")
732952f648SJoseph-Jonathan Salzano     {
742952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Module;
752952f648SJoseph-Jonathan Salzano     }
762952f648SJoseph-Jonathan Salzano     if (chassisType ==
772952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount")
782952f648SJoseph-Jonathan Salzano     {
792952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::RackMount;
802952f648SJoseph-Jonathan Salzano     }
812952f648SJoseph-Jonathan Salzano     if (chassisType ==
822952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone")
832952f648SJoseph-Jonathan Salzano     {
842952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::StandAlone;
852952f648SJoseph-Jonathan Salzano     }
862952f648SJoseph-Jonathan Salzano     if (chassisType ==
872952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure")
882952f648SJoseph-Jonathan Salzano     {
892952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::StorageEnclosure;
902952f648SJoseph-Jonathan Salzano     }
912952f648SJoseph-Jonathan Salzano     if (chassisType ==
922952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone")
932952f648SJoseph-Jonathan Salzano     {
942952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Zone;
952952f648SJoseph-Jonathan Salzano     }
962952f648SJoseph-Jonathan Salzano     return chassis::ChassisType::Invalid;
972952f648SJoseph-Jonathan Salzano }
982952f648SJoseph-Jonathan Salzano 
99e37f8451SRapkiewicz, Pawel /**
1005e577bc1SWilly Tu  * @brief Retrieves resources over dbus to link to the chassis
1015e577bc1SWilly Tu  *
1025e577bc1SWilly Tu  * @param[in] asyncResp  - Shared pointer for completing asynchronous
1035e577bc1SWilly Tu  * calls
1045e577bc1SWilly Tu  * @param[in] path       - Chassis dbus path to look for the storage.
1055e577bc1SWilly Tu  *
1065e577bc1SWilly Tu  * Calls the Association endpoints on the path + "/storage" and add the link of
1075e577bc1SWilly Tu  * json["Links"]["Storage@odata.count"] =
1085e577bc1SWilly Tu  *    {"@odata.id", "/redfish/v1/Storage/" + resourceId}
1095e577bc1SWilly Tu  *
1105e577bc1SWilly Tu  * @return None.
1115e577bc1SWilly Tu  */
1125e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1135e577bc1SWilly Tu                            const sdbusplus::message::object_path& path)
1145e577bc1SWilly Tu {
115deae6a78SEd Tanous     dbus::utility::getProperty<std::vector<std::string>>(
116deae6a78SEd Tanous         "xyz.openbmc_project.ObjectMapper", (path / "storage").str,
117deae6a78SEd Tanous         "xyz.openbmc_project.Association", "endpoints",
118d4b054c1SWilly Tu         [asyncResp](const boost::system::error_code& ec,
1195e577bc1SWilly Tu                     const std::vector<std::string>& storageList) {
1205e577bc1SWilly Tu             if (ec)
1215e577bc1SWilly Tu             {
12262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error");
1235e577bc1SWilly Tu                 return;
1245e577bc1SWilly Tu             }
1255e577bc1SWilly Tu 
1265e577bc1SWilly Tu             nlohmann::json::array_t storages;
1275e577bc1SWilly Tu             for (const std::string& storagePath : storageList)
1285e577bc1SWilly Tu             {
1295e577bc1SWilly Tu                 std::string id =
1305e577bc1SWilly Tu                     sdbusplus::message::object_path(storagePath).filename();
1315e577bc1SWilly Tu                 if (id.empty())
1325e577bc1SWilly Tu                 {
1335e577bc1SWilly Tu                     continue;
1345e577bc1SWilly Tu                 }
1355e577bc1SWilly Tu 
1365e577bc1SWilly Tu                 nlohmann::json::object_t storage;
137253f11b8SEd Tanous                 storage["@odata.id"] =
138253f11b8SEd Tanous                     boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
139253f11b8SEd Tanous                                         BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
1405e577bc1SWilly Tu                 storages.emplace_back(std::move(storage));
1415e577bc1SWilly Tu             }
1425e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
1435e577bc1SWilly Tu                 storages.size();
1445e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
1455e577bc1SWilly Tu         });
1465e577bc1SWilly Tu }
1475e577bc1SWilly Tu 
1485e577bc1SWilly Tu /**
149beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
150beeca0aeSGunnar Mills  *
151ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
152beeca0aeSGunnar Mills  *
153beeca0aeSGunnar Mills  * @return None.
154beeca0aeSGunnar Mills  */
155ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
156beeca0aeSGunnar Mills {
157deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
158deae6a78SEd Tanous         "xyz.openbmc_project.State.Chassis",
1591e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1601e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
161ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1621e1e598dSJonathan Doman                                           const std::string& chassisState) {
163beeca0aeSGunnar Mills             if (ec)
164beeca0aeSGunnar Mills             {
165a6e5e0abSCarson Labrado                 if (ec == boost::system::errc::host_unreachable)
166a6e5e0abSCarson Labrado                 {
167a6e5e0abSCarson Labrado                     // Service not available, no error, just don't return
168a6e5e0abSCarson Labrado                     // chassis state info
16962598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Service not available {}", ec);
170a6e5e0abSCarson Labrado                     return;
171a6e5e0abSCarson Labrado                 }
17262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
173ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
174beeca0aeSGunnar Mills                 return;
175beeca0aeSGunnar Mills             }
176beeca0aeSGunnar Mills 
17762598e31SEd Tanous             BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
178beeca0aeSGunnar Mills             // Verify Chassis State
179bd79bce8SPatrick Williams             if (chassisState ==
180bd79bce8SPatrick Williams                 "xyz.openbmc_project.State.Chassis.PowerState.On")
181beeca0aeSGunnar Mills             {
182bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
183bd79bce8SPatrick Williams                     resource::PowerState::On;
184539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
185539d8c6bSEd Tanous                     resource::State::Enabled;
186beeca0aeSGunnar Mills             }
1871e1e598dSJonathan Doman             else if (chassisState ==
188beeca0aeSGunnar Mills                      "xyz.openbmc_project.State.Chassis.PowerState.Off")
189beeca0aeSGunnar Mills             {
190bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
191bd79bce8SPatrick Williams                     resource::PowerState::Off;
192539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
193539d8c6bSEd Tanous                     resource::State::StandbyOffline;
194beeca0aeSGunnar Mills             }
1951e1e598dSJonathan Doman         });
196beeca0aeSGunnar Mills }
197beeca0aeSGunnar Mills 
198c181942fSQiang XU /**
199c181942fSQiang XU  * Retrieves physical security properties over dbus
200c181942fSQiang XU  */
2017164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
2027164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
203e99073f5SGeorge Liu     const boost::system::error_code& ec,
2047164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
2057164bc62SChau Ly {
206c181942fSQiang XU     if (ec)
207c181942fSQiang XU     {
2084e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
209c181942fSQiang XU         //     mandatory property
21062598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
211c181942fSQiang XU         return;
212c181942fSQiang XU     }
213c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
214c181942fSQiang XU     for (const auto& object : subtree)
215c181942fSQiang XU     {
216840a9ffcSPatrick Williams         if (!object.second.empty())
217c181942fSQiang XU         {
21889144a3aSEd Tanous             const auto& service = object.second.front();
2197164bc62SChau Ly 
2207164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
2217164bc62SChau Ly 
222deae6a78SEd Tanous             dbus::utility::getProperty<std::string>(
223deae6a78SEd Tanous                 service.first, object.first,
2247164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
2257164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
2267164bc62SChau Ly                             const std::string& value) {
2277164bc62SChau Ly                     if (ec1)
2287164bc62SChau Ly                     {
229bd79bce8SPatrick Williams                         // do not add err msg in redfish response, because this
230bd79bce8SPatrick Williams                         // is not
2317164bc62SChau Ly                         //     mandatory property
2327164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
2337164bc62SChau Ly                         return;
2347164bc62SChau Ly                     }
235bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["PhysicalSecurity"]
236bd79bce8SPatrick Williams                                             ["IntrusionSensorNumber"] = 1;
2377164bc62SChau Ly                     asyncResp->res
238bd79bce8SPatrick Williams                         .jsonValue["PhysicalSecurity"]["IntrusionSensor"] =
239bd79bce8SPatrick Williams                         value;
2407164bc62SChau Ly                 });
2417164bc62SChau Ly 
242c181942fSQiang XU             return;
243c181942fSQiang XU         }
244c181942fSQiang XU     }
245c181942fSQiang XU }
246c181942fSQiang XU 
247cf7eba09SNan Zhou inline void handleChassisCollectionGet(
248cf7eba09SNan Zhou     App& app, const crow::Request& req,
249cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2501abe55efSEd Tanous {
2513ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
25245ca1b86SEd Tanous     {
25345ca1b86SEd Tanous         return;
25445ca1b86SEd Tanous     }
2558d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
2568d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
2578d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
2588d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
259e37f8451SRapkiewicz, Pawel 
26002f6ff19SGunnar Mills     collection_util::getCollectionMembers(
2613f95a277SMyung Bae         asyncResp, boost::urls::url("/redfish/v1/Chassis"), chassisInterfaces,
26236b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
263cf7eba09SNan Zhou }
264cf7eba09SNan Zhou 
265a5617496SJie Yang inline void getChassisContainedBy(
266a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
267a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
26828ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths)
269a5617496SJie Yang {
270a5617496SJie Yang     if (ec)
271a5617496SJie Yang     {
272a5617496SJie Yang         if (ec.value() != EBADR)
273a5617496SJie Yang         {
27462598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
275a5617496SJie Yang             messages::internalError(asyncResp->res);
276a5617496SJie Yang         }
277a5617496SJie Yang         return;
278a5617496SJie Yang     }
279a5617496SJie Yang     if (upstreamChassisPaths.empty())
280a5617496SJie Yang     {
281a5617496SJie Yang         return;
282a5617496SJie Yang     }
283a5617496SJie Yang     if (upstreamChassisPaths.size() > 1)
284a5617496SJie Yang     {
2858ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId);
286a5617496SJie Yang         messages::internalError(asyncResp->res);
287a5617496SJie Yang         return;
288a5617496SJie Yang     }
289a5617496SJie Yang 
290a5617496SJie Yang     sdbusplus::message::object_path upstreamChassisPath(
291a5617496SJie Yang         upstreamChassisPaths[0]);
292a5617496SJie Yang     std::string upstreamChassis = upstreamChassisPath.filename();
293a5617496SJie Yang     if (upstreamChassis.empty())
294a5617496SJie Yang     {
29562598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
29662598e31SEd Tanous                            upstreamChassisPath.str, chassisId);
297a5617496SJie Yang         return;
298a5617496SJie Yang     }
299a5617496SJie Yang 
300a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
301a5617496SJie Yang         boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
302a5617496SJie Yang }
303a5617496SJie Yang 
304a5617496SJie Yang inline void getChassisContains(
305a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
306a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
30728ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths)
308a5617496SJie Yang {
309a5617496SJie Yang     if (ec)
310a5617496SJie Yang     {
311a5617496SJie Yang         if (ec.value() != EBADR)
312a5617496SJie Yang         {
31362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
314a5617496SJie Yang             messages::internalError(asyncResp->res);
315a5617496SJie Yang         }
316a5617496SJie Yang         return;
317a5617496SJie Yang     }
318a5617496SJie Yang     if (downstreamChassisPaths.empty())
319a5617496SJie Yang     {
320a5617496SJie Yang         return;
321a5617496SJie Yang     }
322a5617496SJie Yang     nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
323a5617496SJie Yang     if (!jValue.is_array())
324a5617496SJie Yang     {
325a5617496SJie Yang         // Create the array if it was empty
326a5617496SJie Yang         jValue = nlohmann::json::array();
327a5617496SJie Yang     }
328a5617496SJie Yang     for (const auto& p : downstreamChassisPaths)
329a5617496SJie Yang     {
330a5617496SJie Yang         sdbusplus::message::object_path downstreamChassisPath(p);
331a5617496SJie Yang         std::string downstreamChassis = downstreamChassisPath.filename();
332a5617496SJie Yang         if (downstreamChassis.empty())
333a5617496SJie Yang         {
33462598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
33562598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
336a5617496SJie Yang             continue;
337a5617496SJie Yang         }
338a5617496SJie Yang         nlohmann::json link;
339bd79bce8SPatrick Williams         link["@odata.id"] =
340bd79bce8SPatrick Williams             boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis);
341a5617496SJie Yang         jValue.push_back(std::move(link));
342a5617496SJie Yang     }
343a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
344a5617496SJie Yang }
345a5617496SJie Yang 
346bd79bce8SPatrick Williams inline void getChassisConnectivity(
347bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
348bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& chassisPath)
349a5617496SJie Yang {
35062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
351a5617496SJie Yang 
35228ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
353a5617496SJie Yang         chassisPath + "/contained_by",
35428ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
3553f95a277SMyung Bae         chassisInterfaces,
356a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
357a5617496SJie Yang 
35828ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
359a5617496SJie Yang         chassisPath + "/containing",
36028ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
3613f95a277SMyung Bae         chassisInterfaces,
3623f95a277SMyung Bae         std::bind_front(getChassisContains, asyncResp, chassisId));
363a5617496SJie Yang }
364a5617496SJie Yang 
365cf7eba09SNan Zhou /**
366cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
367cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
368cf7eba09SNan Zhou  */
369cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
370cf7eba09SNan Zhou {
371cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
372cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
373cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
374cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
37562d5e2e4SEd Tanous }
376e37f8451SRapkiewicz, Pawel 
377bd79bce8SPatrick Williams inline void getChassisLocationCode(
378bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
379bd79bce8SPatrick Williams     const std::string& connectionName, const std::string& path)
380308f70c7SWilly Tu {
381deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
382deae6a78SEd Tanous         connectionName, path,
3831e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3845e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3851e1e598dSJonathan Doman                     const std::string& property) {
386308f70c7SWilly Tu             if (ec)
387308f70c7SWilly Tu             {
38862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Location");
389308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
390308f70c7SWilly Tu                 return;
391308f70c7SWilly Tu             }
392308f70c7SWilly Tu 
393bd79bce8SPatrick Williams             asyncResp->res
394bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3951e1e598dSJonathan Doman                 property;
3961e1e598dSJonathan Doman         });
397308f70c7SWilly Tu }
398308f70c7SWilly Tu 
399308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
400308f70c7SWilly Tu                            const std::string& connectionName,
401308f70c7SWilly Tu                            const std::string& path)
402308f70c7SWilly Tu {
403deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
404deae6a78SEd Tanous         connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID",
4055e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
4061e1e598dSJonathan Doman                     const std::string& chassisUUID) {
407308f70c7SWilly Tu             if (ec)
408308f70c7SWilly Tu             {
40962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for UUID");
410308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
411308f70c7SWilly Tu                 return;
412308f70c7SWilly Tu             }
4131e1e598dSJonathan Doman             asyncResp->res.jsonValue["UUID"] = chassisUUID;
4141e1e598dSJonathan Doman         });
415308f70c7SWilly Tu }
416308f70c7SWilly Tu 
4177164bc62SChau Ly inline void handleDecoratorAssetProperties(
41845ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4197164bc62SChau Ly     const std::string& chassisId, const std::string& path,
4207164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
421cf7eba09SNan Zhou {
422*f7e62c14SMyung Bae     asset_utils::extractAssetInfo(asyncResp, ""_json_pointer, propertiesList,
423*f7e62c14SMyung Bae                                   true);
4247164bc62SChau Ly 
4257164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4267164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
42725b54dbaSEd Tanous 
42825b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
42925b54dbaSEd Tanous     {
4307164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4317164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4327164bc62SChau Ly         // Power object
4337164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4347164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
43525b54dbaSEd Tanous     }
43625b54dbaSEd Tanous 
43725b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
43825b54dbaSEd Tanous     {
4397164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4407164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4417164bc62SChau Ly                                 chassisId);
4427164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
44325b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
44425b54dbaSEd Tanous                                 chassisId);
4457164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4467164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4477164bc62SChau Ly                                 chassisId);
44825b54dbaSEd Tanous     }
4497164bc62SChau Ly     // SensorCollection
4507164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4517164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
452539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
4537164bc62SChau Ly 
4547164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4557164bc62SChau Ly     nlohmann::json::object_t system;
456bd79bce8SPatrick Williams     system["@odata.id"] =
457bd79bce8SPatrick Williams         std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
4587164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4597164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4607164bc62SChau Ly         std::move(computerSystems);
4617164bc62SChau Ly 
4627164bc62SChau Ly     nlohmann::json::array_t managedBy;
4637164bc62SChau Ly     nlohmann::json::object_t manager;
464253f11b8SEd Tanous     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
465253f11b8SEd Tanous                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
4667164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4677164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4687164bc62SChau Ly     getChassisState(asyncResp);
4697164bc62SChau Ly     getStorageLink(asyncResp, path);
4707164bc62SChau Ly }
4717164bc62SChau Ly 
4722952f648SJoseph-Jonathan Salzano inline void handleChassisProperties(
4732952f648SJoseph-Jonathan Salzano     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4742952f648SJoseph-Jonathan Salzano     const dbus::utility::DBusPropertiesMap& propertiesList)
4752952f648SJoseph-Jonathan Salzano {
4762952f648SJoseph-Jonathan Salzano     const std::string* type = nullptr;
4772952f648SJoseph-Jonathan Salzano 
4782952f648SJoseph-Jonathan Salzano     const bool success = sdbusplus::unpackPropertiesNoThrow(
4792952f648SJoseph-Jonathan Salzano         dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type);
4802952f648SJoseph-Jonathan Salzano 
4812952f648SJoseph-Jonathan Salzano     if (!success)
4822952f648SJoseph-Jonathan Salzano     {
4832952f648SJoseph-Jonathan Salzano         messages::internalError(asyncResp->res);
4842952f648SJoseph-Jonathan Salzano         return;
4852952f648SJoseph-Jonathan Salzano     }
4862952f648SJoseph-Jonathan Salzano 
48719ea2864SGunnar Mills     // Chassis Type is a required property in Redfish
48819ea2864SGunnar Mills     // If there is an error or some enum we don't support just sit it to Rack
48919ea2864SGunnar Mills     // Mount
49019ea2864SGunnar Mills     asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount;
49119ea2864SGunnar Mills 
4922952f648SJoseph-Jonathan Salzano     if (type != nullptr)
4932952f648SJoseph-Jonathan Salzano     {
4942952f648SJoseph-Jonathan Salzano         auto chassisType = translateChassisTypeToRedfish(*type);
4952952f648SJoseph-Jonathan Salzano         if (chassisType != chassis::ChassisType::Invalid)
4962952f648SJoseph-Jonathan Salzano         {
4972952f648SJoseph-Jonathan Salzano             asyncResp->res.jsonValue["ChassisType"] = chassisType;
4982952f648SJoseph-Jonathan Salzano         }
4992952f648SJoseph-Jonathan Salzano     }
5002952f648SJoseph-Jonathan Salzano }
5012952f648SJoseph-Jonathan Salzano 
5027164bc62SChau Ly inline void handleChassisGetSubTree(
5037164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5047164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
5057164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
5067164bc62SChau Ly {
50762d5e2e4SEd Tanous     if (ec)
5081abe55efSEd Tanous     {
50962598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
510f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
511daf36e2eSEd Tanous         return;
512daf36e2eSEd Tanous     }
513daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
514cf7eba09SNan Zhou     for (const std::pair<
515cf7eba09SNan Zhou              std::string,
516cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
5171214b7e7SGunnar Mills              object : subtree)
5181abe55efSEd Tanous     {
519daf36e2eSEd Tanous         const std::string& path = object.first;
520cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
5211214b7e7SGunnar Mills             connectionNames = object.second;
5227e860f15SJohn Edward Broadbent 
523997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
524997093ebSGeorge Liu         if (objPath.filename() != chassisId)
5251abe55efSEd Tanous         {
526daf36e2eSEd Tanous             continue;
527daf36e2eSEd Tanous         }
52826f03899SShawn McCarney 
529a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
530a5617496SJie Yang 
53126f6976fSEd Tanous         if (connectionNames.empty())
5321abe55efSEd Tanous         {
53362598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
534e0d918bcSEd Tanous             continue;
535daf36e2eSEd Tanous         }
536e0d918bcSEd Tanous 
5377164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
53849c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
539ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
54049c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
541cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
5427164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
5437164bc62SChau Ly                                 chassisId);
5441476687dSEd Tanous         asyncResp->res
545cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
546ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
547ef4c65b7SEd Tanous                                 chassisId);
5486c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
5496c3e9451SGeorge Liu             path + "/drive",
5507164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
5516c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
55292903bd4SJohn Edward Broadbent                 if (ec3 || resp.empty())
55392903bd4SJohn Edward Broadbent                 {
55492903bd4SJohn Edward Broadbent                     return; // no drives = no failures
55592903bd4SJohn Edward Broadbent                 }
55692903bd4SJohn Edward Broadbent 
55792903bd4SJohn Edward Broadbent                 nlohmann::json reference;
558bd79bce8SPatrick Williams                 reference["@odata.id"] = boost::urls::format(
559bd79bce8SPatrick Williams                     "/redfish/v1/Chassis/{}/Drives", chassisId);
56092903bd4SJohn Edward Broadbent                 asyncResp->res.jsonValue["Drives"] = std::move(reference);
56192903bd4SJohn Edward Broadbent             });
56292903bd4SJohn Edward Broadbent 
563002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
5641c8fba97SJames Feist 
5657164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
566e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
567e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
5681c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5690fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5701c8fba97SJames Feist 
571476b9cc5STejas Patil         const std::string assetTagInterface =
5720fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
573523d4868SLogananth Sundararaj         const std::string replaceableInterface =
574523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
575b4d593f1SCarson Labrado         const std::string revisionInterface =
576b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
577523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
578523d4868SLogananth Sundararaj         {
579523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
580476b9cc5STejas Patil             {
581deae6a78SEd Tanous                 dbus::utility::getProperty<std::string>(
582deae6a78SEd Tanous                     connectionName, path, assetTagInterface, "AssetTag",
5837164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5841e1e598dSJonathan Doman                                            const std::string& property) {
5858a592810SEd Tanous                         if (ec2)
586476b9cc5STejas Patil                         {
587bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
588bd79bce8SPatrick Williams                                 "DBus response error for AssetTag: {}", ec2);
589476b9cc5STejas Patil                             messages::internalError(asyncResp->res);
590476b9cc5STejas Patil                             return;
591476b9cc5STejas Patil                         }
592002d39b4SEd Tanous                         asyncResp->res.jsonValue["AssetTag"] = property;
5931e1e598dSJonathan Doman                     });
594476b9cc5STejas Patil             }
595523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
596523d4868SLogananth Sundararaj             {
597deae6a78SEd Tanous                 dbus::utility::getProperty<bool>(
598deae6a78SEd Tanous                     connectionName, path, replaceableInterface, "HotPluggable",
5997164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
600523d4868SLogananth Sundararaj                                            const bool property) {
601523d4868SLogananth Sundararaj                         if (ec2)
602523d4868SLogananth Sundararaj                         {
60362598e31SEd Tanous                             BMCWEB_LOG_ERROR(
604bd79bce8SPatrick Williams                                 "DBus response error for HotPluggable: {}",
605bd79bce8SPatrick Williams                                 ec2);
606523d4868SLogananth Sundararaj                             messages::internalError(asyncResp->res);
607523d4868SLogananth Sundararaj                             return;
608523d4868SLogananth Sundararaj                         }
609523d4868SLogananth Sundararaj                         asyncResp->res.jsonValue["HotPluggable"] = property;
610523d4868SLogananth Sundararaj                     });
611523d4868SLogananth Sundararaj             }
612b4d593f1SCarson Labrado             else if (interface == revisionInterface)
613b4d593f1SCarson Labrado             {
614deae6a78SEd Tanous                 dbus::utility::getProperty<std::string>(
615deae6a78SEd Tanous                     connectionName, path, revisionInterface, "Version",
616b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
617b4d593f1SCarson Labrado                                            const std::string& property) {
618b4d593f1SCarson Labrado                         if (ec2)
619b4d593f1SCarson Labrado                         {
620bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
621bd79bce8SPatrick Williams                                 "DBus response error for Version: {}", ec2);
622b4d593f1SCarson Labrado                             messages::internalError(asyncResp->res);
623b4d593f1SCarson Labrado                             return;
624b4d593f1SCarson Labrado                         }
625b4d593f1SCarson Labrado                         asyncResp->res.jsonValue["Version"] = property;
626b4d593f1SCarson Labrado                     });
627b4d593f1SCarson Labrado             }
628523d4868SLogananth Sundararaj         }
629476b9cc5STejas Patil 
6301c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
6311c8fba97SJames Feist         {
6327164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
6331c8fba97SJames Feist             {
634f664fd8aSJanet Adkins                 if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED)
635f664fd8aSJanet Adkins                 {
6361c8fba97SJames Feist                     getIndicatorLedState(asyncResp);
637f664fd8aSJanet Adkins                 }
638de8e5144SJanet Adkins                 getLocationIndicatorActive(asyncResp, objPath);
6391c8fba97SJames Feist                 break;
6401c8fba97SJames Feist             }
6411c8fba97SJames Feist         }
6421c8fba97SJames Feist 
643deae6a78SEd Tanous         dbus::utility::getAllProperties(
64486d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
64586d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
6467164bc62SChau Ly             [asyncResp, chassisId,
6477164bc62SChau Ly              path](const boost::system::error_code&,
648cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
6497164bc62SChau Ly                 handleDecoratorAssetProperties(asyncResp, chassisId, path,
6507164bc62SChau Ly                                                propertiesList);
65186d89ed7SKrzysztof Grobelny             });
6522c37b4b0SSharad Yadav 
65346f780f7SEd Tanous         dbus::utility::getAllProperties(
6542952f648SJoseph-Jonathan Salzano             *crow::connections::systemBus, connectionName, path,
6552952f648SJoseph-Jonathan Salzano             "xyz.openbmc_project.Inventory.Item.Chassis",
6562952f648SJoseph-Jonathan Salzano             [asyncResp](
6572952f648SJoseph-Jonathan Salzano                 const boost::system::error_code&,
6582952f648SJoseph-Jonathan Salzano                 const dbus::utility::DBusPropertiesMap& propertiesList) {
6592952f648SJoseph-Jonathan Salzano                 handleChassisProperties(asyncResp, propertiesList);
6602952f648SJoseph-Jonathan Salzano             });
6612952f648SJoseph-Jonathan Salzano 
662308f70c7SWilly Tu         for (const auto& interface : interfaces2)
6632c37b4b0SSharad Yadav         {
664308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
6652c37b4b0SSharad Yadav             {
666308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
6672c37b4b0SSharad Yadav             }
668cf7eba09SNan Zhou             else if (interface ==
6690fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6702c37b4b0SSharad Yadav             {
671002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6722c37b4b0SSharad Yadav             }
6732c37b4b0SSharad Yadav         }
6742c37b4b0SSharad Yadav 
675daf36e2eSEd Tanous         return;
676daf36e2eSEd Tanous     }
677e0d918bcSEd Tanous 
678daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
679d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6807164bc62SChau Ly }
681c181942fSQiang XU 
682504af5a0SPatrick Williams inline void handleChassisGet(
683504af5a0SPatrick Williams     App& app, const crow::Request& req,
6847164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6857164bc62SChau Ly     const std::string& chassisId)
6867164bc62SChau Ly {
6877164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6887164bc62SChau Ly     {
6897164bc62SChau Ly         return;
6907164bc62SChau Ly     }
6917164bc62SChau Ly 
6927164bc62SChau Ly     dbus::utility::getSubTree(
6933f95a277SMyung Bae         "/xyz/openbmc_project/inventory", 0, chassisInterfaces,
6947164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6957164bc62SChau Ly 
6967164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6977164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6987164bc62SChau Ly 
6997164bc62SChau Ly     dbus::utility::getSubTree(
7007164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
7017164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
702cf7eba09SNan Zhou }
7031c8fba97SJames Feist 
704504af5a0SPatrick Williams inline void handleChassisPatch(
705504af5a0SPatrick Williams     App& app, const crow::Request& req,
7067e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
707cf7eba09SNan Zhou     const std::string& param)
708cf7eba09SNan Zhou {
7093ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
71045ca1b86SEd Tanous     {
71145ca1b86SEd Tanous         return;
71245ca1b86SEd Tanous     }
7139f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
7141c8fba97SJames Feist     std::optional<std::string> indicatorLed;
7151c8fba97SJames Feist 
7167e860f15SJohn Edward Broadbent     if (param.empty())
7171c8fba97SJames Feist     {
7181c8fba97SJames Feist         return;
7191c8fba97SJames Feist     }
7201c8fba97SJames Feist 
721afc474aeSMyung Bae     if (!json_util::readJsonPatch(                             //
722afc474aeSMyung Bae             req, asyncResp->res,                               //
723afc474aeSMyung Bae             "IndicatorLED", indicatorLed,                      //
724afc474aeSMyung Bae             "LocationIndicatorActive", locationIndicatorActive //
725afc474aeSMyung Bae             ))
7261c8fba97SJames Feist     {
7271c8fba97SJames Feist         return;
7281c8fba97SJames Feist     }
7291c8fba97SJames Feist 
7309f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
7311c8fba97SJames Feist     {
7321c8fba97SJames Feist         return; // delete this when we support more patch properties
7331c8fba97SJames Feist     }
734d6aa0093SGunnar Mills     if (indicatorLed)
735d6aa0093SGunnar Mills     {
736f664fd8aSJanet Adkins         if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED)
737f664fd8aSJanet Adkins         {
7387e860f15SJohn Edward Broadbent             asyncResp->res.addHeader(
7397e860f15SJohn Edward Broadbent                 boost::beast::http::field::warning,
7400fda0f12SGeorge Liu                 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
741d6aa0093SGunnar Mills         }
742f664fd8aSJanet Adkins         else
743f664fd8aSJanet Adkins         {
744f664fd8aSJanet Adkins             messages::propertyUnknown(asyncResp->res, "IndicatorLED");
745f664fd8aSJanet Adkins             return;
746f664fd8aSJanet Adkins         }
747f664fd8aSJanet Adkins     }
7481c8fba97SJames Feist 
7497e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
7501c8fba97SJames Feist 
751e99073f5SGeorge Liu     dbus::utility::getSubTree(
7523f95a277SMyung Bae         "/xyz/openbmc_project/inventory", 0, chassisInterfaces,
753cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
7545e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
755b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7561c8fba97SJames Feist             if (ec)
7571c8fba97SJames Feist             {
75862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
7591c8fba97SJames Feist                 messages::internalError(asyncResp->res);
7601c8fba97SJames Feist                 return;
7611c8fba97SJames Feist             }
7621c8fba97SJames Feist 
7631c8fba97SJames Feist             // Iterate over all retrieved ObjectPaths.
764bd79bce8SPatrick Williams             for (const std::pair<std::string,
765bd79bce8SPatrick Williams                                  std::vector<std::pair<
766bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
7671214b7e7SGunnar Mills                      object : subtree)
7681c8fba97SJames Feist             {
7691c8fba97SJames Feist                 const std::string& path = object.first;
770bd79bce8SPatrick Williams                 const std::vector<
771bd79bce8SPatrick Williams                     std::pair<std::string, std::vector<std::string>>>&
7721214b7e7SGunnar Mills                     connectionNames = object.second;
7731c8fba97SJames Feist 
774997093ebSGeorge Liu                 sdbusplus::message::object_path objPath(path);
775997093ebSGeorge Liu                 if (objPath.filename() != chassisId)
7761c8fba97SJames Feist                 {
7771c8fba97SJames Feist                     continue;
7781c8fba97SJames Feist                 }
7791c8fba97SJames Feist 
78026f6976fSEd Tanous                 if (connectionNames.empty())
7811c8fba97SJames Feist                 {
78262598e31SEd Tanous                     BMCWEB_LOG_ERROR("Got 0 Connection names");
7831c8fba97SJames Feist                     continue;
7841c8fba97SJames Feist                 }
7851c8fba97SJames Feist 
78623a21a1cSEd Tanous                 const std::vector<std::string>& interfaces3 =
7871c8fba97SJames Feist                     connectionNames[0].second;
7881c8fba97SJames Feist 
789e5ae9c1cSGeorge Liu                 const std::array<const char*, 3> hasIndicatorLed = {
790e5ae9c1cSGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Chassis",
7911c8fba97SJames Feist                     "xyz.openbmc_project.Inventory.Item.Panel",
7920fda0f12SGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7931c8fba97SJames Feist                 bool indicatorChassis = false;
7941c8fba97SJames Feist                 for (const char* interface : hasIndicatorLed)
7951c8fba97SJames Feist                 {
7963544d2a7SEd Tanous                     if (std::ranges::find(interfaces3, interface) !=
7973544d2a7SEd Tanous                         interfaces3.end())
7981c8fba97SJames Feist                     {
7991c8fba97SJames Feist                         indicatorChassis = true;
8001c8fba97SJames Feist                         break;
8011c8fba97SJames Feist                     }
8021c8fba97SJames Feist                 }
8039f8bfa7cSGunnar Mills                 if (locationIndicatorActive)
8049f8bfa7cSGunnar Mills                 {
8059f8bfa7cSGunnar Mills                     if (indicatorChassis)
8069f8bfa7cSGunnar Mills                     {
807de8e5144SJanet Adkins                         setLocationIndicatorActive(asyncResp, path,
808de8e5144SJanet Adkins                                                    *locationIndicatorActive);
8099f8bfa7cSGunnar Mills                     }
8109f8bfa7cSGunnar Mills                     else
8119f8bfa7cSGunnar Mills                     {
812002d39b4SEd Tanous                         messages::propertyUnknown(asyncResp->res,
813002d39b4SEd Tanous                                                   "LocationIndicatorActive");
8149f8bfa7cSGunnar Mills                     }
8159f8bfa7cSGunnar Mills                 }
816f664fd8aSJanet Adkins                 if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED)
817f664fd8aSJanet Adkins                 {
8189f8bfa7cSGunnar Mills                     if (indicatorLed)
8199f8bfa7cSGunnar Mills                     {
8201c8fba97SJames Feist                         if (indicatorChassis)
8211c8fba97SJames Feist                         {
822f23b7296SEd Tanous                             setIndicatorLedState(asyncResp, *indicatorLed);
8231c8fba97SJames Feist                         }
8241c8fba97SJames Feist                         else
8251c8fba97SJames Feist                         {
826bd79bce8SPatrick Williams                             messages::propertyUnknown(asyncResp->res,
827bd79bce8SPatrick Williams                                                       "IndicatorLED");
8281c8fba97SJames Feist                         }
8291c8fba97SJames Feist                     }
830f664fd8aSJanet Adkins                 }
8311c8fba97SJames Feist                 return;
8321c8fba97SJames Feist             }
8331c8fba97SJames Feist 
834d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
835e99073f5SGeorge Liu         });
836cf7eba09SNan Zhou }
837cf7eba09SNan Zhou 
838cf7eba09SNan Zhou /**
839cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
840cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
841cf7eba09SNan Zhou  */
842cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
843cf7eba09SNan Zhou {
844cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
845cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
846cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
847cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
848cf7eba09SNan Zhou 
849cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
850cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
851cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
852cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
8531c8fba97SJames Feist }
854dd99e04bSP.K. Lee 
855504af5a0SPatrick Williams inline void doChassisPowerCycle(
856504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
857dd99e04bSP.K. Lee {
8587a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
859c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
860c3b3c92aSVijay Khemka 
861c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
8627a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
8637a1dbc48SGeorge Liu         "/", 0, interfaces,
864b9d36b47SEd Tanous         [asyncResp](
8657a1dbc48SGeorge Liu             const boost::system::error_code& ec,
866b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
867c3b3c92aSVijay Khemka             if (ec)
868c3b3c92aSVijay Khemka             {
86962598e31SEd Tanous                 BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
870c3b3c92aSVijay Khemka                 messages::internalError(asyncResp->res);
871c3b3c92aSVijay Khemka                 return;
872c3b3c92aSVijay Khemka             }
873c3b3c92aSVijay Khemka 
874dd99e04bSP.K. Lee             const char* processName = "xyz.openbmc_project.State.Chassis";
875dd99e04bSP.K. Lee             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
876dd99e04bSP.K. Lee             const char* destProperty = "RequestedPowerTransition";
877dd99e04bSP.K. Lee             const std::string propertyValue =
878dd99e04bSP.K. Lee                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
879bd79bce8SPatrick Williams             std::string objectPath =
880bd79bce8SPatrick Williams                 "/xyz/openbmc_project/state/chassis_system0";
881c3b3c92aSVijay Khemka 
882c3b3c92aSVijay Khemka             /* Look for system reset chassis path */
883bd79bce8SPatrick Williams             if ((std::ranges::find(chassisList, objectPath)) ==
884bd79bce8SPatrick Williams                 chassisList.end())
885c3b3c92aSVijay Khemka             {
886c3b3c92aSVijay Khemka                 /* We prefer to reset the full chassis_system, but if it doesn't
887c3b3c92aSVijay Khemka                  * exist on some platforms, fall back to a host-only power reset
888c3b3c92aSVijay Khemka                  */
889c3b3c92aSVijay Khemka                 objectPath = "/xyz/openbmc_project/state/chassis0";
890c3b3c92aSVijay Khemka             }
891dd99e04bSP.K. Lee 
892e93abac6SGinu George             setDbusProperty(asyncResp, "ResetType", processName, objectPath,
893e93abac6SGinu George                             interfaceName, destProperty, propertyValue);
8947a1dbc48SGeorge Liu         });
895dd99e04bSP.K. Lee }
896dd99e04bSP.K. Lee 
897cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
898cf7eba09SNan Zhou     App& app, const crow::Request& req,
8997e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
900cf7eba09SNan Zhou     const std::string& /*chassisId*/)
901cf7eba09SNan Zhou {
9023ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
90345ca1b86SEd Tanous     {
90445ca1b86SEd Tanous         return;
90545ca1b86SEd Tanous     }
90662598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
907dd99e04bSP.K. Lee 
908dd99e04bSP.K. Lee     std::string resetType;
909dd99e04bSP.K. Lee 
910cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
911dd99e04bSP.K. Lee     {
912dd99e04bSP.K. Lee         return;
913dd99e04bSP.K. Lee     }
914dd99e04bSP.K. Lee 
915dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
916dd99e04bSP.K. Lee     {
91762598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
918002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
919002d39b4SEd Tanous                                               "ResetType");
920dd99e04bSP.K. Lee 
921dd99e04bSP.K. Lee         return;
922dd99e04bSP.K. Lee     }
923dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
924dd99e04bSP.K. Lee }
9251cb1a9e6SAppaRao Puli 
9261cb1a9e6SAppaRao Puli /**
927cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
928cf7eba09SNan Zhou  * action.
929cf7eba09SNan Zhou  * Function handles POST method request.
930cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
9311cb1a9e6SAppaRao Puli  */
932cf7eba09SNan Zhou 
933cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
9341cb1a9e6SAppaRao Puli {
935cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
936cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
937cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
938cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
939cf7eba09SNan Zhou }
940cf7eba09SNan Zhou 
941cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
942cf7eba09SNan Zhou     App& app, const crow::Request& req,
9437e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
944cf7eba09SNan Zhou     const std::string& chassisId)
945cf7eba09SNan Zhou {
9463ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
9471cb1a9e6SAppaRao Puli     {
94845ca1b86SEd Tanous         return;
94945ca1b86SEd Tanous     }
950cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
951ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
952ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
9531476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
9541476687dSEd Tanous 
9551476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
9565b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
9575b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
9585b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
9595b9e95a1SNan Zhou     parameter["Required"] = true;
960539d8c6bSEd Tanous     parameter["DataType"] = action_info::ParameterTypes::String;
9611476687dSEd Tanous     nlohmann::json::array_t allowed;
962ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
9635b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
964ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
9655b9e95a1SNan Zhou 
9661476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
967cf7eba09SNan Zhou }
968cf7eba09SNan Zhou 
969cf7eba09SNan Zhou /**
970cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
971cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
972cf7eba09SNan Zhou  */
973cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
974cf7eba09SNan Zhou {
975cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
976cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
977cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
978cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9791cb1a9e6SAppaRao Puli }
9801cb1a9e6SAppaRao Puli 
981e37f8451SRapkiewicz, Pawel } // namespace redfish
982