xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision deae6a789444debc4724fb6902fc5def299afbee)
1e37f8451SRapkiewicz, Pawel /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15e37f8451SRapkiewicz, Pawel */
16e37f8451SRapkiewicz, Pawel #pragma once
17e37f8451SRapkiewicz, Pawel 
183ccb3adbSEd Tanous #include "app.hpp"
197a1dbc48SGeorge Liu #include "dbus_utility.hpp"
20539d8c6bSEd Tanous #include "generated/enums/action_info.hpp"
21539d8c6bSEd Tanous #include "generated/enums/chassis.hpp"
22539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
231c8fba97SJames Feist #include "led.hpp"
243ccb3adbSEd Tanous #include "query.hpp"
257164bc62SChau Ly #include "redfish_util.hpp"
263ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
273ccb3adbSEd Tanous #include "utils/collection.hpp"
283ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
29cf7eba09SNan Zhou #include "utils/json_utils.hpp"
301abe55efSEd Tanous 
31e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
32ef4c65b7SEd Tanous #include <boost/url/format.hpp>
331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
34fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp>
3586d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
361214b7e7SGunnar Mills 
377a1dbc48SGeorge Liu #include <array>
382952f648SJoseph-Jonathan Salzano #include <memory>
393544d2a7SEd Tanous #include <ranges>
407a1dbc48SGeorge Liu #include <string_view>
417a1dbc48SGeorge Liu 
421abe55efSEd Tanous namespace redfish
431abe55efSEd Tanous {
44e37f8451SRapkiewicz, Pawel 
452952f648SJoseph-Jonathan Salzano inline chassis::ChassisType
462952f648SJoseph-Jonathan Salzano     translateChassisTypeToRedfish(const std::string_view& chassisType)
472952f648SJoseph-Jonathan Salzano {
482952f648SJoseph-Jonathan Salzano     if (chassisType ==
492952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade")
502952f648SJoseph-Jonathan Salzano     {
512952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Blade;
522952f648SJoseph-Jonathan Salzano     }
532952f648SJoseph-Jonathan Salzano     if (chassisType ==
542952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component")
552952f648SJoseph-Jonathan Salzano     {
562952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Component;
572952f648SJoseph-Jonathan Salzano     }
582952f648SJoseph-Jonathan Salzano     if (chassisType ==
592952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure")
602952f648SJoseph-Jonathan Salzano     {
612952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Enclosure;
622952f648SJoseph-Jonathan Salzano     }
632952f648SJoseph-Jonathan Salzano     if (chassisType ==
642952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module")
652952f648SJoseph-Jonathan Salzano     {
662952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Module;
672952f648SJoseph-Jonathan Salzano     }
682952f648SJoseph-Jonathan Salzano     if (chassisType ==
692952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount")
702952f648SJoseph-Jonathan Salzano     {
712952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::RackMount;
722952f648SJoseph-Jonathan Salzano     }
732952f648SJoseph-Jonathan Salzano     if (chassisType ==
742952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone")
752952f648SJoseph-Jonathan Salzano     {
762952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::StandAlone;
772952f648SJoseph-Jonathan Salzano     }
782952f648SJoseph-Jonathan Salzano     if (chassisType ==
792952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure")
802952f648SJoseph-Jonathan Salzano     {
812952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::StorageEnclosure;
822952f648SJoseph-Jonathan Salzano     }
832952f648SJoseph-Jonathan Salzano     if (chassisType ==
842952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone")
852952f648SJoseph-Jonathan Salzano     {
862952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Zone;
872952f648SJoseph-Jonathan Salzano     }
882952f648SJoseph-Jonathan Salzano     return chassis::ChassisType::Invalid;
892952f648SJoseph-Jonathan Salzano }
902952f648SJoseph-Jonathan Salzano 
91e37f8451SRapkiewicz, Pawel /**
925e577bc1SWilly Tu  * @brief Retrieves resources over dbus to link to the chassis
935e577bc1SWilly Tu  *
945e577bc1SWilly Tu  * @param[in] asyncResp  - Shared pointer for completing asynchronous
955e577bc1SWilly Tu  * calls
965e577bc1SWilly Tu  * @param[in] path       - Chassis dbus path to look for the storage.
975e577bc1SWilly Tu  *
985e577bc1SWilly Tu  * Calls the Association endpoints on the path + "/storage" and add the link of
995e577bc1SWilly Tu  * json["Links"]["Storage@odata.count"] =
1005e577bc1SWilly Tu  *    {"@odata.id", "/redfish/v1/Storage/" + resourceId}
1015e577bc1SWilly Tu  *
1025e577bc1SWilly Tu  * @return None.
1035e577bc1SWilly Tu  */
1045e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1055e577bc1SWilly Tu                            const sdbusplus::message::object_path& path)
1065e577bc1SWilly Tu {
107*deae6a78SEd Tanous     dbus::utility::getProperty<std::vector<std::string>>(
108*deae6a78SEd Tanous         "xyz.openbmc_project.ObjectMapper", (path / "storage").str,
109*deae6a78SEd Tanous         "xyz.openbmc_project.Association", "endpoints",
110d4b054c1SWilly Tu         [asyncResp](const boost::system::error_code& ec,
1115e577bc1SWilly Tu                     const std::vector<std::string>& storageList) {
1125e577bc1SWilly Tu             if (ec)
1135e577bc1SWilly Tu             {
11462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error");
1155e577bc1SWilly Tu                 return;
1165e577bc1SWilly Tu             }
1175e577bc1SWilly Tu 
1185e577bc1SWilly Tu             nlohmann::json::array_t storages;
1195e577bc1SWilly Tu             for (const std::string& storagePath : storageList)
1205e577bc1SWilly Tu             {
1215e577bc1SWilly Tu                 std::string id =
1225e577bc1SWilly Tu                     sdbusplus::message::object_path(storagePath).filename();
1235e577bc1SWilly Tu                 if (id.empty())
1245e577bc1SWilly Tu                 {
1255e577bc1SWilly Tu                     continue;
1265e577bc1SWilly Tu                 }
1275e577bc1SWilly Tu 
1285e577bc1SWilly Tu                 nlohmann::json::object_t storage;
129253f11b8SEd Tanous                 storage["@odata.id"] =
130253f11b8SEd Tanous                     boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
131253f11b8SEd Tanous                                         BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
1325e577bc1SWilly Tu                 storages.emplace_back(std::move(storage));
1335e577bc1SWilly Tu             }
1345e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
1355e577bc1SWilly Tu                 storages.size();
1365e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
1375e577bc1SWilly Tu         });
1385e577bc1SWilly Tu }
1395e577bc1SWilly Tu 
1405e577bc1SWilly Tu /**
141beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
142beeca0aeSGunnar Mills  *
143ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
144beeca0aeSGunnar Mills  *
145beeca0aeSGunnar Mills  * @return None.
146beeca0aeSGunnar Mills  */
147ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
148beeca0aeSGunnar Mills {
1491e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
150*deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
151*deae6a78SEd Tanous         "xyz.openbmc_project.State.Chassis",
1521e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1531e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
154ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1551e1e598dSJonathan Doman                                           const std::string& chassisState) {
156beeca0aeSGunnar Mills             if (ec)
157beeca0aeSGunnar Mills             {
158a6e5e0abSCarson Labrado                 if (ec == boost::system::errc::host_unreachable)
159a6e5e0abSCarson Labrado                 {
160a6e5e0abSCarson Labrado                     // Service not available, no error, just don't return
161a6e5e0abSCarson Labrado                     // chassis state info
16262598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Service not available {}", ec);
163a6e5e0abSCarson Labrado                     return;
164a6e5e0abSCarson Labrado                 }
16562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
166ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
167beeca0aeSGunnar Mills                 return;
168beeca0aeSGunnar Mills             }
169beeca0aeSGunnar Mills 
17062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
171beeca0aeSGunnar Mills             // Verify Chassis State
172bd79bce8SPatrick Williams             if (chassisState ==
173bd79bce8SPatrick Williams                 "xyz.openbmc_project.State.Chassis.PowerState.On")
174beeca0aeSGunnar Mills             {
175bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
176bd79bce8SPatrick Williams                     resource::PowerState::On;
177539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
178539d8c6bSEd Tanous                     resource::State::Enabled;
179beeca0aeSGunnar Mills             }
1801e1e598dSJonathan Doman             else if (chassisState ==
181beeca0aeSGunnar Mills                      "xyz.openbmc_project.State.Chassis.PowerState.Off")
182beeca0aeSGunnar Mills             {
183bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
184bd79bce8SPatrick Williams                     resource::PowerState::Off;
185539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
186539d8c6bSEd Tanous                     resource::State::StandbyOffline;
187beeca0aeSGunnar Mills             }
1881e1e598dSJonathan Doman         });
189beeca0aeSGunnar Mills }
190beeca0aeSGunnar Mills 
191c181942fSQiang XU /**
192c181942fSQiang XU  * Retrieves physical security properties over dbus
193c181942fSQiang XU  */
1947164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
1957164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
196e99073f5SGeorge Liu     const boost::system::error_code& ec,
1977164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
1987164bc62SChau Ly {
199c181942fSQiang XU     if (ec)
200c181942fSQiang XU     {
2014e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
202c181942fSQiang XU         //     mandatory property
20362598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
204c181942fSQiang XU         return;
205c181942fSQiang XU     }
206c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
207c181942fSQiang XU     for (const auto& object : subtree)
208c181942fSQiang XU     {
209840a9ffcSPatrick Williams         if (!object.second.empty())
210c181942fSQiang XU         {
21189144a3aSEd Tanous             const auto& service = object.second.front();
2127164bc62SChau Ly 
2137164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
2147164bc62SChau Ly 
215*deae6a78SEd Tanous             dbus::utility::getProperty<std::string>(
216*deae6a78SEd Tanous                 service.first, object.first,
2177164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
2187164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
2197164bc62SChau Ly                             const std::string& value) {
2207164bc62SChau Ly                     if (ec1)
2217164bc62SChau Ly                     {
222bd79bce8SPatrick Williams                         // do not add err msg in redfish response, because this
223bd79bce8SPatrick Williams                         // is not
2247164bc62SChau Ly                         //     mandatory property
2257164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
2267164bc62SChau Ly                         return;
2277164bc62SChau Ly                     }
228bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["PhysicalSecurity"]
229bd79bce8SPatrick Williams                                             ["IntrusionSensorNumber"] = 1;
2307164bc62SChau Ly                     asyncResp->res
231bd79bce8SPatrick Williams                         .jsonValue["PhysicalSecurity"]["IntrusionSensor"] =
232bd79bce8SPatrick Williams                         value;
2337164bc62SChau Ly                 });
2347164bc62SChau Ly 
235c181942fSQiang XU             return;
236c181942fSQiang XU         }
237c181942fSQiang XU     }
238c181942fSQiang XU }
239c181942fSQiang XU 
240cf7eba09SNan Zhou inline void handleChassisCollectionGet(
241cf7eba09SNan Zhou     App& app, const crow::Request& req,
242cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2431abe55efSEd Tanous {
2443ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
24545ca1b86SEd Tanous     {
24645ca1b86SEd Tanous         return;
24745ca1b86SEd Tanous     }
2488d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
2498d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
2508d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
2518d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
252e37f8451SRapkiewicz, Pawel 
2537a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
2547a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
2557a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
25602f6ff19SGunnar Mills     collection_util::getCollectionMembers(
25736b5f1edSLakshmi Yadlapati         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces,
25836b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
259cf7eba09SNan Zhou }
260cf7eba09SNan Zhou 
261a5617496SJie Yang inline void getChassisContainedBy(
262a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
263a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
26428ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths)
265a5617496SJie Yang {
266a5617496SJie Yang     if (ec)
267a5617496SJie Yang     {
268a5617496SJie Yang         if (ec.value() != EBADR)
269a5617496SJie Yang         {
27062598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
271a5617496SJie Yang             messages::internalError(asyncResp->res);
272a5617496SJie Yang         }
273a5617496SJie Yang         return;
274a5617496SJie Yang     }
275a5617496SJie Yang     if (upstreamChassisPaths.empty())
276a5617496SJie Yang     {
277a5617496SJie Yang         return;
278a5617496SJie Yang     }
279a5617496SJie Yang     if (upstreamChassisPaths.size() > 1)
280a5617496SJie Yang     {
2818ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId);
282a5617496SJie Yang         messages::internalError(asyncResp->res);
283a5617496SJie Yang         return;
284a5617496SJie Yang     }
285a5617496SJie Yang 
286a5617496SJie Yang     sdbusplus::message::object_path upstreamChassisPath(
287a5617496SJie Yang         upstreamChassisPaths[0]);
288a5617496SJie Yang     std::string upstreamChassis = upstreamChassisPath.filename();
289a5617496SJie Yang     if (upstreamChassis.empty())
290a5617496SJie Yang     {
29162598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
29262598e31SEd Tanous                            upstreamChassisPath.str, chassisId);
293a5617496SJie Yang         return;
294a5617496SJie Yang     }
295a5617496SJie Yang 
296a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
297a5617496SJie Yang         boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
298a5617496SJie Yang }
299a5617496SJie Yang 
300a5617496SJie Yang inline void getChassisContains(
301a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
302a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
30328ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths)
304a5617496SJie Yang {
305a5617496SJie Yang     if (ec)
306a5617496SJie Yang     {
307a5617496SJie Yang         if (ec.value() != EBADR)
308a5617496SJie Yang         {
30962598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
310a5617496SJie Yang             messages::internalError(asyncResp->res);
311a5617496SJie Yang         }
312a5617496SJie Yang         return;
313a5617496SJie Yang     }
314a5617496SJie Yang     if (downstreamChassisPaths.empty())
315a5617496SJie Yang     {
316a5617496SJie Yang         return;
317a5617496SJie Yang     }
318a5617496SJie Yang     nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
319a5617496SJie Yang     if (!jValue.is_array())
320a5617496SJie Yang     {
321a5617496SJie Yang         // Create the array if it was empty
322a5617496SJie Yang         jValue = nlohmann::json::array();
323a5617496SJie Yang     }
324a5617496SJie Yang     for (const auto& p : downstreamChassisPaths)
325a5617496SJie Yang     {
326a5617496SJie Yang         sdbusplus::message::object_path downstreamChassisPath(p);
327a5617496SJie Yang         std::string downstreamChassis = downstreamChassisPath.filename();
328a5617496SJie Yang         if (downstreamChassis.empty())
329a5617496SJie Yang         {
33062598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
33162598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
332a5617496SJie Yang             continue;
333a5617496SJie Yang         }
334a5617496SJie Yang         nlohmann::json link;
335bd79bce8SPatrick Williams         link["@odata.id"] =
336bd79bce8SPatrick Williams             boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis);
337a5617496SJie Yang         jValue.push_back(std::move(link));
338a5617496SJie Yang     }
339a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
340a5617496SJie Yang }
341a5617496SJie Yang 
342bd79bce8SPatrick Williams inline void getChassisConnectivity(
343bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
344bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& chassisPath)
345a5617496SJie Yang {
34662598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
347a5617496SJie Yang 
34828ee563eSMyung Bae     constexpr std::array<std::string_view, 2> interfaces{
34928ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Board",
35028ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Chassis"};
35128ee563eSMyung Bae 
35228ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
353a5617496SJie Yang         chassisPath + "/contained_by",
35428ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
35528ee563eSMyung Bae         interfaces,
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,
36128ee563eSMyung Bae         interfaces, std::bind_front(getChassisContains, asyncResp, chassisId));
362a5617496SJie Yang }
363a5617496SJie Yang 
364cf7eba09SNan Zhou /**
365cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
366cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
367cf7eba09SNan Zhou  */
368cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
369cf7eba09SNan Zhou {
370cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
371cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
372cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
373cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
37462d5e2e4SEd Tanous }
375e37f8451SRapkiewicz, Pawel 
376bd79bce8SPatrick Williams inline void getChassisLocationCode(
377bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
378bd79bce8SPatrick Williams     const std::string& connectionName, const std::string& path)
379308f70c7SWilly Tu {
380*deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
381*deae6a78SEd Tanous         connectionName, path,
3821e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3835e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3841e1e598dSJonathan Doman                     const std::string& property) {
385308f70c7SWilly Tu             if (ec)
386308f70c7SWilly Tu             {
38762598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Location");
388308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
389308f70c7SWilly Tu                 return;
390308f70c7SWilly Tu             }
391308f70c7SWilly Tu 
392bd79bce8SPatrick Williams             asyncResp->res
393bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3941e1e598dSJonathan Doman                 property;
3951e1e598dSJonathan Doman         });
396308f70c7SWilly Tu }
397308f70c7SWilly Tu 
398308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
399308f70c7SWilly Tu                            const std::string& connectionName,
400308f70c7SWilly Tu                            const std::string& path)
401308f70c7SWilly Tu {
402*deae6a78SEd Tanous     dbus::utility::getProperty<std::string>(
403*deae6a78SEd Tanous         connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID",
4045e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
4051e1e598dSJonathan Doman                     const std::string& chassisUUID) {
406308f70c7SWilly Tu             if (ec)
407308f70c7SWilly Tu             {
40862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for UUID");
409308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
410308f70c7SWilly Tu                 return;
411308f70c7SWilly Tu             }
4121e1e598dSJonathan Doman             asyncResp->res.jsonValue["UUID"] = chassisUUID;
4131e1e598dSJonathan Doman         });
414308f70c7SWilly Tu }
415308f70c7SWilly Tu 
4167164bc62SChau Ly inline void handleDecoratorAssetProperties(
41745ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4187164bc62SChau Ly     const std::string& chassisId, const std::string& path,
4197164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
420cf7eba09SNan Zhou {
4217164bc62SChau Ly     const std::string* partNumber = nullptr;
4227164bc62SChau Ly     const std::string* serialNumber = nullptr;
4237164bc62SChau Ly     const std::string* manufacturer = nullptr;
4247164bc62SChau Ly     const std::string* model = nullptr;
4257164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
4267164bc62SChau Ly 
4277164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
4287164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
4297164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
4307164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
4317164bc62SChau Ly 
4327164bc62SChau Ly     if (!success)
43345ca1b86SEd Tanous     {
4347164bc62SChau Ly         messages::internalError(asyncResp->res);
43545ca1b86SEd Tanous         return;
43645ca1b86SEd Tanous     }
437734bfe90SGunnar Mills 
4387164bc62SChau Ly     if (partNumber != nullptr)
4397164bc62SChau Ly     {
4407164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
4417164bc62SChau Ly     }
4427164bc62SChau Ly 
4437164bc62SChau Ly     if (serialNumber != nullptr)
4447164bc62SChau Ly     {
4457164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
4467164bc62SChau Ly     }
4477164bc62SChau Ly 
4487164bc62SChau Ly     if (manufacturer != nullptr)
4497164bc62SChau Ly     {
4507164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
4517164bc62SChau Ly     }
4527164bc62SChau Ly 
4537164bc62SChau Ly     if (model != nullptr)
4547164bc62SChau Ly     {
4557164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
4567164bc62SChau Ly     }
4577164bc62SChau Ly 
4587164bc62SChau Ly     // SparePartNumber is optional on D-Bus
4597164bc62SChau Ly     // so skip if it is empty
4607164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
4617164bc62SChau Ly     {
4627164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4637164bc62SChau Ly     }
4647164bc62SChau Ly 
4657164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4667164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
46725b54dbaSEd Tanous 
46825b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
46925b54dbaSEd Tanous     {
4707164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4717164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4727164bc62SChau Ly         // Power object
4737164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4747164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
47525b54dbaSEd Tanous     }
47625b54dbaSEd Tanous 
47725b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
47825b54dbaSEd Tanous     {
4797164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4807164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4817164bc62SChau Ly                                 chassisId);
4827164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
48325b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
48425b54dbaSEd Tanous                                 chassisId);
4857164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4867164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4877164bc62SChau Ly                                 chassisId);
48825b54dbaSEd Tanous     }
4897164bc62SChau Ly     // SensorCollection
4907164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4917164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
492539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
4937164bc62SChau Ly 
4947164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4957164bc62SChau Ly     nlohmann::json::object_t system;
496bd79bce8SPatrick Williams     system["@odata.id"] =
497bd79bce8SPatrick Williams         std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
4987164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4997164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
5007164bc62SChau Ly         std::move(computerSystems);
5017164bc62SChau Ly 
5027164bc62SChau Ly     nlohmann::json::array_t managedBy;
5037164bc62SChau Ly     nlohmann::json::object_t manager;
504253f11b8SEd Tanous     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
505253f11b8SEd Tanous                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
5067164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
5077164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
5087164bc62SChau Ly     getChassisState(asyncResp);
5097164bc62SChau Ly     getStorageLink(asyncResp, path);
5107164bc62SChau Ly }
5117164bc62SChau Ly 
5122952f648SJoseph-Jonathan Salzano inline void handleChassisProperties(
5132952f648SJoseph-Jonathan Salzano     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5142952f648SJoseph-Jonathan Salzano     const dbus::utility::DBusPropertiesMap& propertiesList)
5152952f648SJoseph-Jonathan Salzano {
5162952f648SJoseph-Jonathan Salzano     const std::string* type = nullptr;
5172952f648SJoseph-Jonathan Salzano 
5182952f648SJoseph-Jonathan Salzano     const bool success = sdbusplus::unpackPropertiesNoThrow(
5192952f648SJoseph-Jonathan Salzano         dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type);
5202952f648SJoseph-Jonathan Salzano 
5212952f648SJoseph-Jonathan Salzano     if (!success)
5222952f648SJoseph-Jonathan Salzano     {
5232952f648SJoseph-Jonathan Salzano         messages::internalError(asyncResp->res);
5242952f648SJoseph-Jonathan Salzano         return;
5252952f648SJoseph-Jonathan Salzano     }
5262952f648SJoseph-Jonathan Salzano 
52719ea2864SGunnar Mills     // Chassis Type is a required property in Redfish
52819ea2864SGunnar Mills     // If there is an error or some enum we don't support just sit it to Rack
52919ea2864SGunnar Mills     // Mount
53019ea2864SGunnar Mills     asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount;
53119ea2864SGunnar Mills 
5322952f648SJoseph-Jonathan Salzano     if (type != nullptr)
5332952f648SJoseph-Jonathan Salzano     {
5342952f648SJoseph-Jonathan Salzano         auto chassisType = translateChassisTypeToRedfish(*type);
5352952f648SJoseph-Jonathan Salzano         if (chassisType != chassis::ChassisType::Invalid)
5362952f648SJoseph-Jonathan Salzano         {
5372952f648SJoseph-Jonathan Salzano             asyncResp->res.jsonValue["ChassisType"] = chassisType;
5382952f648SJoseph-Jonathan Salzano         }
5392952f648SJoseph-Jonathan Salzano     }
5402952f648SJoseph-Jonathan Salzano }
5412952f648SJoseph-Jonathan Salzano 
5427164bc62SChau Ly inline void handleChassisGetSubTree(
5437164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5447164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
5457164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
5467164bc62SChau Ly {
54762d5e2e4SEd Tanous     if (ec)
5481abe55efSEd Tanous     {
54962598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
550f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
551daf36e2eSEd Tanous         return;
552daf36e2eSEd Tanous     }
553daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
554cf7eba09SNan Zhou     for (const std::pair<
555cf7eba09SNan Zhou              std::string,
556cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
5571214b7e7SGunnar Mills              object : subtree)
5581abe55efSEd Tanous     {
559daf36e2eSEd Tanous         const std::string& path = object.first;
560cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
5611214b7e7SGunnar Mills             connectionNames = object.second;
5627e860f15SJohn Edward Broadbent 
563997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
564997093ebSGeorge Liu         if (objPath.filename() != chassisId)
5651abe55efSEd Tanous         {
566daf36e2eSEd Tanous             continue;
567daf36e2eSEd Tanous         }
56826f03899SShawn McCarney 
569a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
570a5617496SJie Yang 
57126f6976fSEd Tanous         if (connectionNames.empty())
5721abe55efSEd Tanous         {
57362598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
574e0d918bcSEd Tanous             continue;
575daf36e2eSEd Tanous         }
576e0d918bcSEd Tanous 
5777164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
57849c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
579ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
58049c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
581cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
5827164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
5837164bc62SChau Ly                                 chassisId);
5841476687dSEd Tanous         asyncResp->res
585cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
586ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
587ef4c65b7SEd Tanous                                 chassisId);
5886c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
5896c3e9451SGeorge Liu             path + "/drive",
5907164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
5916c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
59292903bd4SJohn Edward Broadbent                 if (ec3 || resp.empty())
59392903bd4SJohn Edward Broadbent                 {
59492903bd4SJohn Edward Broadbent                     return; // no drives = no failures
59592903bd4SJohn Edward Broadbent                 }
59692903bd4SJohn Edward Broadbent 
59792903bd4SJohn Edward Broadbent                 nlohmann::json reference;
598bd79bce8SPatrick Williams                 reference["@odata.id"] = boost::urls::format(
599bd79bce8SPatrick Williams                     "/redfish/v1/Chassis/{}/Drives", chassisId);
60092903bd4SJohn Edward Broadbent                 asyncResp->res.jsonValue["Drives"] = std::move(reference);
60192903bd4SJohn Edward Broadbent             });
60292903bd4SJohn Edward Broadbent 
603002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
6041c8fba97SJames Feist 
6057164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
606e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
607e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
6081c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
6090fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
6101c8fba97SJames Feist 
611476b9cc5STejas Patil         const std::string assetTagInterface =
6120fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
613523d4868SLogananth Sundararaj         const std::string replaceableInterface =
614523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
615b4d593f1SCarson Labrado         const std::string revisionInterface =
616b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
617523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
618523d4868SLogananth Sundararaj         {
619523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
620476b9cc5STejas Patil             {
621*deae6a78SEd Tanous                 dbus::utility::getProperty<std::string>(
622*deae6a78SEd Tanous                     connectionName, path, assetTagInterface, "AssetTag",
6237164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
6241e1e598dSJonathan Doman                                            const std::string& property) {
6258a592810SEd Tanous                         if (ec2)
626476b9cc5STejas Patil                         {
627bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
628bd79bce8SPatrick Williams                                 "DBus response error for AssetTag: {}", ec2);
629476b9cc5STejas Patil                             messages::internalError(asyncResp->res);
630476b9cc5STejas Patil                             return;
631476b9cc5STejas Patil                         }
632002d39b4SEd Tanous                         asyncResp->res.jsonValue["AssetTag"] = property;
6331e1e598dSJonathan Doman                     });
634476b9cc5STejas Patil             }
635523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
636523d4868SLogananth Sundararaj             {
637*deae6a78SEd Tanous                 dbus::utility::getProperty<bool>(
638*deae6a78SEd Tanous                     connectionName, path, replaceableInterface, "HotPluggable",
6397164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
640523d4868SLogananth Sundararaj                                            const bool property) {
641523d4868SLogananth Sundararaj                         if (ec2)
642523d4868SLogananth Sundararaj                         {
64362598e31SEd Tanous                             BMCWEB_LOG_ERROR(
644bd79bce8SPatrick Williams                                 "DBus response error for HotPluggable: {}",
645bd79bce8SPatrick Williams                                 ec2);
646523d4868SLogananth Sundararaj                             messages::internalError(asyncResp->res);
647523d4868SLogananth Sundararaj                             return;
648523d4868SLogananth Sundararaj                         }
649523d4868SLogananth Sundararaj                         asyncResp->res.jsonValue["HotPluggable"] = property;
650523d4868SLogananth Sundararaj                     });
651523d4868SLogananth Sundararaj             }
652b4d593f1SCarson Labrado             else if (interface == revisionInterface)
653b4d593f1SCarson Labrado             {
654*deae6a78SEd Tanous                 dbus::utility::getProperty<std::string>(
655*deae6a78SEd Tanous                     connectionName, path, revisionInterface, "Version",
656b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
657b4d593f1SCarson Labrado                                            const std::string& property) {
658b4d593f1SCarson Labrado                         if (ec2)
659b4d593f1SCarson Labrado                         {
660bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
661bd79bce8SPatrick Williams                                 "DBus response error for Version: {}", ec2);
662b4d593f1SCarson Labrado                             messages::internalError(asyncResp->res);
663b4d593f1SCarson Labrado                             return;
664b4d593f1SCarson Labrado                         }
665b4d593f1SCarson Labrado                         asyncResp->res.jsonValue["Version"] = property;
666b4d593f1SCarson Labrado                     });
667b4d593f1SCarson Labrado             }
668523d4868SLogananth Sundararaj         }
669476b9cc5STejas Patil 
6701c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
6711c8fba97SJames Feist         {
6727164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
6731c8fba97SJames Feist             {
6741c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
67559a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
6761c8fba97SJames Feist                 break;
6771c8fba97SJames Feist             }
6781c8fba97SJames Feist         }
6791c8fba97SJames Feist 
680*deae6a78SEd Tanous         dbus::utility::getAllProperties(
68186d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
68286d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
6837164bc62SChau Ly             [asyncResp, chassisId,
6847164bc62SChau Ly              path](const boost::system::error_code&,
685cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
6867164bc62SChau Ly                 handleDecoratorAssetProperties(asyncResp, chassisId, path,
6877164bc62SChau Ly                                                propertiesList);
68886d89ed7SKrzysztof Grobelny             });
6892c37b4b0SSharad Yadav 
6902952f648SJoseph-Jonathan Salzano         sdbusplus::asio::getAllProperties(
6912952f648SJoseph-Jonathan Salzano             *crow::connections::systemBus, connectionName, path,
6922952f648SJoseph-Jonathan Salzano             "xyz.openbmc_project.Inventory.Item.Chassis",
6932952f648SJoseph-Jonathan Salzano             [asyncResp](
6942952f648SJoseph-Jonathan Salzano                 const boost::system::error_code&,
6952952f648SJoseph-Jonathan Salzano                 const dbus::utility::DBusPropertiesMap& propertiesList) {
6962952f648SJoseph-Jonathan Salzano                 handleChassisProperties(asyncResp, propertiesList);
6972952f648SJoseph-Jonathan Salzano             });
6982952f648SJoseph-Jonathan Salzano 
699308f70c7SWilly Tu         for (const auto& interface : interfaces2)
7002c37b4b0SSharad Yadav         {
701308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
7022c37b4b0SSharad Yadav             {
703308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
7042c37b4b0SSharad Yadav             }
705cf7eba09SNan Zhou             else if (interface ==
7060fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
7072c37b4b0SSharad Yadav             {
708002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
7092c37b4b0SSharad Yadav             }
7102c37b4b0SSharad Yadav         }
7112c37b4b0SSharad Yadav 
712daf36e2eSEd Tanous         return;
713daf36e2eSEd Tanous     }
714e0d918bcSEd Tanous 
715daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
716d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
7177164bc62SChau Ly }
718c181942fSQiang XU 
7197164bc62SChau Ly inline void
7207164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
7217164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7227164bc62SChau Ly                      const std::string& chassisId)
7237164bc62SChau Ly {
7247164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
7257164bc62SChau Ly     {
7267164bc62SChau Ly         return;
7277164bc62SChau Ly     }
7287164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
7297164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
7307164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
7317164bc62SChau Ly 
7327164bc62SChau Ly     dbus::utility::getSubTree(
7337164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
7347164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
7357164bc62SChau Ly 
7367164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
7377164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
7387164bc62SChau Ly 
7397164bc62SChau Ly     dbus::utility::getSubTree(
7407164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
7417164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
742cf7eba09SNan Zhou }
7431c8fba97SJames Feist 
744cf7eba09SNan Zhou inline void
745cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
7467e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
747cf7eba09SNan Zhou                        const std::string& param)
748cf7eba09SNan Zhou {
7493ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
75045ca1b86SEd Tanous     {
75145ca1b86SEd Tanous         return;
75245ca1b86SEd Tanous     }
7539f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
7541c8fba97SJames Feist     std::optional<std::string> indicatorLed;
7551c8fba97SJames Feist 
7567e860f15SJohn Edward Broadbent     if (param.empty())
7571c8fba97SJames Feist     {
7581c8fba97SJames Feist         return;
7591c8fba97SJames Feist     }
7601c8fba97SJames Feist 
761afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
762afc474aeSMyung Bae             req, asyncResp->res, //
763afc474aeSMyung Bae             "IndicatorLED", indicatorLed, //
764afc474aeSMyung Bae             "LocationIndicatorActive", locationIndicatorActive //
765afc474aeSMyung Bae             ))
7661c8fba97SJames Feist     {
7671c8fba97SJames Feist         return;
7681c8fba97SJames Feist     }
7691c8fba97SJames Feist 
7709f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
7719f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
7721c8fba97SJames Feist     {
7731c8fba97SJames Feist         return; // delete this when we support more patch properties
7741c8fba97SJames Feist     }
775d6aa0093SGunnar Mills     if (indicatorLed)
776d6aa0093SGunnar Mills     {
7777e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
7787e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
7790fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
780d6aa0093SGunnar Mills     }
7811c8fba97SJames Feist 
782e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
7831c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
7841c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
7851c8fba97SJames Feist 
7867e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
7871c8fba97SJames Feist 
788e99073f5SGeorge Liu     dbus::utility::getSubTree(
789e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
790cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
7915e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
792b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7931c8fba97SJames Feist             if (ec)
7941c8fba97SJames Feist             {
79562598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
7961c8fba97SJames Feist                 messages::internalError(asyncResp->res);
7971c8fba97SJames Feist                 return;
7981c8fba97SJames Feist             }
7991c8fba97SJames Feist 
8001c8fba97SJames Feist             // Iterate over all retrieved ObjectPaths.
801bd79bce8SPatrick Williams             for (const std::pair<std::string,
802bd79bce8SPatrick Williams                                  std::vector<std::pair<
803bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
8041214b7e7SGunnar Mills                      object : subtree)
8051c8fba97SJames Feist             {
8061c8fba97SJames Feist                 const std::string& path = object.first;
807bd79bce8SPatrick Williams                 const std::vector<
808bd79bce8SPatrick Williams                     std::pair<std::string, std::vector<std::string>>>&
8091214b7e7SGunnar Mills                     connectionNames = object.second;
8101c8fba97SJames Feist 
811997093ebSGeorge Liu                 sdbusplus::message::object_path objPath(path);
812997093ebSGeorge Liu                 if (objPath.filename() != chassisId)
8131c8fba97SJames Feist                 {
8141c8fba97SJames Feist                     continue;
8151c8fba97SJames Feist                 }
8161c8fba97SJames Feist 
81726f6976fSEd Tanous                 if (connectionNames.empty())
8181c8fba97SJames Feist                 {
81962598e31SEd Tanous                     BMCWEB_LOG_ERROR("Got 0 Connection names");
8201c8fba97SJames Feist                     continue;
8211c8fba97SJames Feist                 }
8221c8fba97SJames Feist 
82323a21a1cSEd Tanous                 const std::vector<std::string>& interfaces3 =
8241c8fba97SJames Feist                     connectionNames[0].second;
8251c8fba97SJames Feist 
826e5ae9c1cSGeorge Liu                 const std::array<const char*, 3> hasIndicatorLed = {
827e5ae9c1cSGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Chassis",
8281c8fba97SJames Feist                     "xyz.openbmc_project.Inventory.Item.Panel",
8290fda0f12SGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
8301c8fba97SJames Feist                 bool indicatorChassis = false;
8311c8fba97SJames Feist                 for (const char* interface : hasIndicatorLed)
8321c8fba97SJames Feist                 {
8333544d2a7SEd Tanous                     if (std::ranges::find(interfaces3, interface) !=
8343544d2a7SEd Tanous                         interfaces3.end())
8351c8fba97SJames Feist                     {
8361c8fba97SJames Feist                         indicatorChassis = true;
8371c8fba97SJames Feist                         break;
8381c8fba97SJames Feist                     }
8391c8fba97SJames Feist                 }
8409f8bfa7cSGunnar Mills                 if (locationIndicatorActive)
8419f8bfa7cSGunnar Mills                 {
8429f8bfa7cSGunnar Mills                     if (indicatorChassis)
8439f8bfa7cSGunnar Mills                     {
844bd79bce8SPatrick Williams                         setSystemLocationIndicatorActive(
845bd79bce8SPatrick Williams                             asyncResp, *locationIndicatorActive);
8469f8bfa7cSGunnar Mills                     }
8479f8bfa7cSGunnar Mills                     else
8489f8bfa7cSGunnar Mills                     {
849002d39b4SEd Tanous                         messages::propertyUnknown(asyncResp->res,
850002d39b4SEd Tanous                                                   "LocationIndicatorActive");
8519f8bfa7cSGunnar Mills                     }
8529f8bfa7cSGunnar Mills                 }
8539f8bfa7cSGunnar Mills                 if (indicatorLed)
8549f8bfa7cSGunnar Mills                 {
8551c8fba97SJames Feist                     if (indicatorChassis)
8561c8fba97SJames Feist                     {
857f23b7296SEd Tanous                         setIndicatorLedState(asyncResp, *indicatorLed);
8581c8fba97SJames Feist                     }
8591c8fba97SJames Feist                     else
8601c8fba97SJames Feist                     {
861bd79bce8SPatrick Williams                         messages::propertyUnknown(asyncResp->res,
862bd79bce8SPatrick Williams                                                   "IndicatorLED");
8631c8fba97SJames Feist                     }
8641c8fba97SJames Feist                 }
8651c8fba97SJames Feist                 return;
8661c8fba97SJames Feist             }
8671c8fba97SJames Feist 
868d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
869e99073f5SGeorge Liu         });
870cf7eba09SNan Zhou }
871cf7eba09SNan Zhou 
872cf7eba09SNan Zhou /**
873cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
874cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
875cf7eba09SNan Zhou  */
876cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
877cf7eba09SNan Zhou {
878cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
879cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
880cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
881cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
882cf7eba09SNan Zhou 
883cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
884cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
885cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
886cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
8871c8fba97SJames Feist }
888dd99e04bSP.K. Lee 
8898d1b46d7Szhanghch05 inline void
8908d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
891dd99e04bSP.K. Lee {
8927a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
893c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
894c3b3c92aSVijay Khemka 
895c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
8967a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
8977a1dbc48SGeorge Liu         "/", 0, interfaces,
898b9d36b47SEd Tanous         [asyncResp](
8997a1dbc48SGeorge Liu             const boost::system::error_code& ec,
900b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
901c3b3c92aSVijay Khemka             if (ec)
902c3b3c92aSVijay Khemka             {
90362598e31SEd Tanous                 BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
904c3b3c92aSVijay Khemka                 messages::internalError(asyncResp->res);
905c3b3c92aSVijay Khemka                 return;
906c3b3c92aSVijay Khemka             }
907c3b3c92aSVijay Khemka 
908dd99e04bSP.K. Lee             const char* processName = "xyz.openbmc_project.State.Chassis";
909dd99e04bSP.K. Lee             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
910dd99e04bSP.K. Lee             const char* destProperty = "RequestedPowerTransition";
911dd99e04bSP.K. Lee             const std::string propertyValue =
912dd99e04bSP.K. Lee                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
913bd79bce8SPatrick Williams             std::string objectPath =
914bd79bce8SPatrick Williams                 "/xyz/openbmc_project/state/chassis_system0";
915c3b3c92aSVijay Khemka 
916c3b3c92aSVijay Khemka             /* Look for system reset chassis path */
917bd79bce8SPatrick Williams             if ((std::ranges::find(chassisList, objectPath)) ==
918bd79bce8SPatrick Williams                 chassisList.end())
919c3b3c92aSVijay Khemka             {
920c3b3c92aSVijay Khemka                 /* We prefer to reset the full chassis_system, but if it doesn't
921c3b3c92aSVijay Khemka                  * exist on some platforms, fall back to a host-only power reset
922c3b3c92aSVijay Khemka                  */
923c3b3c92aSVijay Khemka                 objectPath = "/xyz/openbmc_project/state/chassis0";
924c3b3c92aSVijay Khemka             }
925dd99e04bSP.K. Lee 
926e93abac6SGinu George             setDbusProperty(asyncResp, "ResetType", processName, objectPath,
927e93abac6SGinu George                             interfaceName, destProperty, propertyValue);
9287a1dbc48SGeorge Liu         });
929dd99e04bSP.K. Lee }
930dd99e04bSP.K. Lee 
931cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
932cf7eba09SNan Zhou     App& app, const crow::Request& req,
9337e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
934cf7eba09SNan Zhou     const std::string& /*chassisId*/)
935cf7eba09SNan Zhou {
9363ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
93745ca1b86SEd Tanous     {
93845ca1b86SEd Tanous         return;
93945ca1b86SEd Tanous     }
94062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
941dd99e04bSP.K. Lee 
942dd99e04bSP.K. Lee     std::string resetType;
943dd99e04bSP.K. Lee 
944cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
945dd99e04bSP.K. Lee     {
946dd99e04bSP.K. Lee         return;
947dd99e04bSP.K. Lee     }
948dd99e04bSP.K. Lee 
949dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
950dd99e04bSP.K. Lee     {
95162598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
952002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
953002d39b4SEd Tanous                                               "ResetType");
954dd99e04bSP.K. Lee 
955dd99e04bSP.K. Lee         return;
956dd99e04bSP.K. Lee     }
957dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
958dd99e04bSP.K. Lee }
9591cb1a9e6SAppaRao Puli 
9601cb1a9e6SAppaRao Puli /**
961cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
962cf7eba09SNan Zhou  * action.
963cf7eba09SNan Zhou  * Function handles POST method request.
964cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
9651cb1a9e6SAppaRao Puli  */
966cf7eba09SNan Zhou 
967cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
9681cb1a9e6SAppaRao Puli {
969cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
970cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
971cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
972cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
973cf7eba09SNan Zhou }
974cf7eba09SNan Zhou 
975cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
976cf7eba09SNan Zhou     App& app, const crow::Request& req,
9777e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
978cf7eba09SNan Zhou     const std::string& chassisId)
979cf7eba09SNan Zhou {
9803ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
9811cb1a9e6SAppaRao Puli     {
98245ca1b86SEd Tanous         return;
98345ca1b86SEd Tanous     }
984cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
985ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
986ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
9871476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
9881476687dSEd Tanous 
9891476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
9905b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
9915b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
9925b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
9935b9e95a1SNan Zhou     parameter["Required"] = true;
994539d8c6bSEd Tanous     parameter["DataType"] = action_info::ParameterTypes::String;
9951476687dSEd Tanous     nlohmann::json::array_t allowed;
996ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
9975b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
998ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
9995b9e95a1SNan Zhou 
10001476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
1001cf7eba09SNan Zhou }
1002cf7eba09SNan Zhou 
1003cf7eba09SNan Zhou /**
1004cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
1005cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
1006cf7eba09SNan Zhou  */
1007cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
1008cf7eba09SNan Zhou {
1009cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
1010cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
1011cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
1012cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
10131cb1a9e6SAppaRao Puli }
10141cb1a9e6SAppaRao Puli 
1015e37f8451SRapkiewicz, Pawel } // namespace redfish
1016