xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 9ae226fabb21700e6a73ef1d0a9d1cdead70fea5)
1e37f8451SRapkiewicz, Pawel /*
2e37f8451SRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation
3e37f8451SRapkiewicz, Pawel //
4e37f8451SRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License");
5e37f8451SRapkiewicz, Pawel // you may not use this file except in compliance with the License.
6e37f8451SRapkiewicz, Pawel // You may obtain a copy of the License at
7e37f8451SRapkiewicz, Pawel //
8e37f8451SRapkiewicz, Pawel //      http://www.apache.org/licenses/LICENSE-2.0
9e37f8451SRapkiewicz, Pawel //
10e37f8451SRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software
11e37f8451SRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS,
12e37f8451SRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e37f8451SRapkiewicz, Pawel // See the License for the specific language governing permissions and
14e37f8451SRapkiewicz, Pawel // limitations under the License.
15e37f8451SRapkiewicz, Pawel */
16e37f8451SRapkiewicz, Pawel #pragma once
17e37f8451SRapkiewicz, Pawel 
1813451e39SWilly Tu #include "bmcweb_config.h"
1913451e39SWilly Tu 
203ccb3adbSEd Tanous #include "app.hpp"
217a1dbc48SGeorge Liu #include "dbus_utility.hpp"
22b49ac873SJames Feist #include "health.hpp"
231c8fba97SJames Feist #include "led.hpp"
243ccb3adbSEd Tanous #include "query.hpp"
253ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
263ccb3adbSEd Tanous #include "utils/collection.hpp"
273ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
28cf7eba09SNan Zhou #include "utils/json_utils.hpp"
291abe55efSEd Tanous 
30e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
31ef4c65b7SEd Tanous #include <boost/url/format.hpp>
321e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
33fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp>
3486d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
351214b7e7SGunnar Mills 
367a1dbc48SGeorge Liu #include <array>
377a1dbc48SGeorge Liu #include <string_view>
387a1dbc48SGeorge Liu 
391abe55efSEd Tanous namespace redfish
401abe55efSEd Tanous {
41e37f8451SRapkiewicz, Pawel 
42e37f8451SRapkiewicz, Pawel /**
435e577bc1SWilly Tu  * @brief Retrieves resources over dbus to link to the chassis
445e577bc1SWilly Tu  *
455e577bc1SWilly Tu  * @param[in] asyncResp  - Shared pointer for completing asynchronous
465e577bc1SWilly Tu  * calls
475e577bc1SWilly Tu  * @param[in] path       - Chassis dbus path to look for the storage.
485e577bc1SWilly Tu  *
495e577bc1SWilly Tu  * Calls the Association endpoints on the path + "/storage" and add the link of
505e577bc1SWilly Tu  * json["Links"]["Storage@odata.count"] =
515e577bc1SWilly Tu  *    {"@odata.id", "/redfish/v1/Storage/" + resourceId}
525e577bc1SWilly Tu  *
535e577bc1SWilly Tu  * @return None.
545e577bc1SWilly Tu  */
555e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
565e577bc1SWilly Tu                            const sdbusplus::message::object_path& path)
575e577bc1SWilly Tu {
585e577bc1SWilly Tu     sdbusplus::asio::getProperty<std::vector<std::string>>(
595e577bc1SWilly Tu         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
605e577bc1SWilly Tu         (path / "storage").str, "xyz.openbmc_project.Association", "endpoints",
61d4b054c1SWilly Tu         [asyncResp](const boost::system::error_code& ec,
625e577bc1SWilly Tu                     const std::vector<std::string>& storageList) {
635e577bc1SWilly Tu         if (ec)
645e577bc1SWilly Tu         {
655e577bc1SWilly Tu             BMCWEB_LOG_DEBUG << "getStorageLink got DBUS response error";
665e577bc1SWilly Tu             return;
675e577bc1SWilly Tu         }
685e577bc1SWilly Tu 
695e577bc1SWilly Tu         nlohmann::json::array_t storages;
705e577bc1SWilly Tu         for (const std::string& storagePath : storageList)
715e577bc1SWilly Tu         {
725e577bc1SWilly Tu             std::string id =
735e577bc1SWilly Tu                 sdbusplus::message::object_path(storagePath).filename();
745e577bc1SWilly Tu             if (id.empty())
755e577bc1SWilly Tu             {
765e577bc1SWilly Tu                 continue;
775e577bc1SWilly Tu             }
785e577bc1SWilly Tu 
795e577bc1SWilly Tu             nlohmann::json::object_t storage;
805e577bc1SWilly Tu             storage["@odata.id"] = boost::urls::format(
815e577bc1SWilly Tu                 "/redfish/v1/Systems/system/Storage/{}", id);
825e577bc1SWilly Tu             storages.emplace_back(std::move(storage));
835e577bc1SWilly Tu         }
845e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
855e577bc1SWilly Tu             storages.size();
865e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
875e577bc1SWilly Tu         });
885e577bc1SWilly Tu }
895e577bc1SWilly Tu 
905e577bc1SWilly Tu /**
91beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
92beeca0aeSGunnar Mills  *
93ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
94beeca0aeSGunnar Mills  *
95beeca0aeSGunnar Mills  * @return None.
96beeca0aeSGunnar Mills  */
97ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
98beeca0aeSGunnar Mills {
991e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
1001e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1011e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1021e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1031e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
104ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1051e1e598dSJonathan Doman                                           const std::string& chassisState) {
106beeca0aeSGunnar Mills         if (ec)
107beeca0aeSGunnar Mills         {
108a6e5e0abSCarson Labrado             if (ec == boost::system::errc::host_unreachable)
109a6e5e0abSCarson Labrado             {
110a6e5e0abSCarson Labrado                 // Service not available, no error, just don't return
111a6e5e0abSCarson Labrado                 // chassis state info
112a6e5e0abSCarson Labrado                 BMCWEB_LOG_DEBUG << "Service not available " << ec;
113a6e5e0abSCarson Labrado                 return;
114a6e5e0abSCarson Labrado             }
115ac106bf6SEd Tanous             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
116ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
117beeca0aeSGunnar Mills             return;
118beeca0aeSGunnar Mills         }
119beeca0aeSGunnar Mills 
1201e1e598dSJonathan Doman         BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState;
121beeca0aeSGunnar Mills         // Verify Chassis State
122002d39b4SEd Tanous         if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
123beeca0aeSGunnar Mills         {
124ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "On";
125ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
126beeca0aeSGunnar Mills         }
1271e1e598dSJonathan Doman         else if (chassisState ==
128beeca0aeSGunnar Mills                  "xyz.openbmc_project.State.Chassis.PowerState.Off")
129beeca0aeSGunnar Mills         {
130ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "Off";
131ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
132beeca0aeSGunnar Mills         }
1331e1e598dSJonathan Doman         });
134beeca0aeSGunnar Mills }
135beeca0aeSGunnar Mills 
136ac106bf6SEd Tanous inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
137c181942fSQiang XU                                   const std::string& service,
138c181942fSQiang XU                                   const std::string& objPath)
139c181942fSQiang XU {
140c181942fSQiang XU     BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
141c181942fSQiang XU 
1421e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1431e1e598dSJonathan Doman         *crow::connections::systemBus, service, objPath,
1441e1e598dSJonathan Doman         "xyz.openbmc_project.Chassis.Intrusion", "Status",
145ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1461e1e598dSJonathan Doman                                           const std::string& value) {
147c181942fSQiang XU         if (ec)
148c181942fSQiang XU         {
1494e0453b1SGunnar Mills             // do not add err msg in redfish response, because this is not
150c181942fSQiang XU             //     mandatory property
151c181942fSQiang XU             BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
152c181942fSQiang XU             return;
153c181942fSQiang XU         }
154c181942fSQiang XU 
155ac106bf6SEd Tanous         asyncResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] =
156ac106bf6SEd Tanous             1;
157ac106bf6SEd Tanous         asyncResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
1581e1e598dSJonathan Doman         });
159c181942fSQiang XU }
160c181942fSQiang XU 
161c181942fSQiang XU /**
162c181942fSQiang XU  * Retrieves physical security properties over dbus
163c181942fSQiang XU  */
164ac106bf6SEd Tanous inline void
165ac106bf6SEd Tanous     getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
166c181942fSQiang XU {
167e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
168e99073f5SGeorge Liu         "xyz.openbmc_project.Chassis.Intrusion"};
169e99073f5SGeorge Liu     dbus::utility::getSubTree(
170e99073f5SGeorge Liu         "/xyz/openbmc_project/Intrusion", 1, interfaces,
171ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](
172e99073f5SGeorge Liu             const boost::system::error_code& ec,
173b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
174c181942fSQiang XU         if (ec)
175c181942fSQiang XU         {
1764e0453b1SGunnar Mills             // do not add err msg in redfish response, because this is not
177c181942fSQiang XU             //     mandatory property
178002d39b4SEd Tanous             BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n";
179c181942fSQiang XU             return;
180c181942fSQiang XU         }
181c181942fSQiang XU         // Iterate over all retrieved ObjectPaths.
182c181942fSQiang XU         for (const auto& object : subtree)
183c181942fSQiang XU         {
184840a9ffcSPatrick Williams             if (!object.second.empty())
185c181942fSQiang XU             {
186840a9ffcSPatrick Williams                 const auto service = object.second.front();
187ac106bf6SEd Tanous                 getIntrusionByService(asyncResp, service.first, object.first);
188c181942fSQiang XU                 return;
189c181942fSQiang XU             }
190c181942fSQiang XU         }
191e99073f5SGeorge Liu         });
192c181942fSQiang XU }
193c181942fSQiang XU 
194cf7eba09SNan Zhou inline void handleChassisCollectionGet(
195cf7eba09SNan Zhou     App& app, const crow::Request& req,
196cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1971abe55efSEd Tanous {
1983ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
19945ca1b86SEd Tanous     {
20045ca1b86SEd Tanous         return;
20145ca1b86SEd Tanous     }
2028d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
2038d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
2048d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
2058d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
206e37f8451SRapkiewicz, Pawel 
2077a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
2087a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
2097a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
21002f6ff19SGunnar Mills     collection_util::getCollectionMembers(
2117a1dbc48SGeorge Liu         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces);
212cf7eba09SNan Zhou }
213cf7eba09SNan Zhou 
214cf7eba09SNan Zhou /**
215cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
216cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
217cf7eba09SNan Zhou  */
218cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
219cf7eba09SNan Zhou {
220cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
221cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
222cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
223cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
22462d5e2e4SEd Tanous }
225e37f8451SRapkiewicz, Pawel 
226308f70c7SWilly Tu inline void
227308f70c7SWilly Tu     getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
228308f70c7SWilly Tu                            const std::string& connectionName,
229308f70c7SWilly Tu                            const std::string& path)
230308f70c7SWilly Tu {
2311e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
2321e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
2331e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
2345e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
2351e1e598dSJonathan Doman                     const std::string& property) {
236308f70c7SWilly Tu         if (ec)
237308f70c7SWilly Tu         {
23851dab2a7SAndrew Geissler             BMCWEB_LOG_ERROR << "DBUS response error for Location";
239308f70c7SWilly Tu             messages::internalError(asyncResp->res);
240308f70c7SWilly Tu             return;
241308f70c7SWilly Tu         }
242308f70c7SWilly Tu 
243002d39b4SEd Tanous         asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
2441e1e598dSJonathan Doman             property;
2451e1e598dSJonathan Doman         });
246308f70c7SWilly Tu }
247308f70c7SWilly Tu 
248308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
249308f70c7SWilly Tu                            const std::string& connectionName,
250308f70c7SWilly Tu                            const std::string& path)
251308f70c7SWilly Tu {
2521e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
2531e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
2541e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
2555e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
2561e1e598dSJonathan Doman                     const std::string& chassisUUID) {
257308f70c7SWilly Tu         if (ec)
258308f70c7SWilly Tu         {
25951dab2a7SAndrew Geissler             BMCWEB_LOG_ERROR << "DBUS response error for UUID";
260308f70c7SWilly Tu             messages::internalError(asyncResp->res);
261308f70c7SWilly Tu             return;
262308f70c7SWilly Tu         }
2631e1e598dSJonathan Doman         asyncResp->res.jsonValue["UUID"] = chassisUUID;
2641e1e598dSJonathan Doman         });
265308f70c7SWilly Tu }
266308f70c7SWilly Tu 
267cf7eba09SNan Zhou inline void
268cf7eba09SNan Zhou     handleChassisGet(App& app, const crow::Request& req,
26945ca1b86SEd Tanous                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
270cf7eba09SNan Zhou                      const std::string& chassisId)
271cf7eba09SNan Zhou {
2723ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
27345ca1b86SEd Tanous     {
27445ca1b86SEd Tanous         return;
27545ca1b86SEd Tanous     }
276e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
277734bfe90SGunnar Mills         "xyz.openbmc_project.Inventory.Item.Board",
278adc4f0dbSShawn McCarney         "xyz.openbmc_project.Inventory.Item.Chassis"};
279734bfe90SGunnar Mills 
280e99073f5SGeorge Liu     dbus::utility::getSubTree(
281e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
28262d5e2e4SEd Tanous         [asyncResp, chassisId(std::string(chassisId))](
283e99073f5SGeorge Liu             const boost::system::error_code& ec,
284b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
28562d5e2e4SEd Tanous         if (ec)
2861abe55efSEd Tanous         {
28751dab2a7SAndrew Geissler             BMCWEB_LOG_ERROR << "DBUS response error " << ec;
288f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
289daf36e2eSEd Tanous             return;
290daf36e2eSEd Tanous         }
291daf36e2eSEd Tanous         // Iterate over all retrieved ObjectPaths.
292cf7eba09SNan Zhou         for (const std::pair<
293cf7eba09SNan Zhou                  std::string,
294cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
2951214b7e7SGunnar Mills                  object : subtree)
2961abe55efSEd Tanous         {
297daf36e2eSEd Tanous             const std::string& path = object.first;
298cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
2991214b7e7SGunnar Mills                 connectionNames = object.second;
3007e860f15SJohn Edward Broadbent 
301997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
302997093ebSGeorge Liu             if (objPath.filename() != chassisId)
3031abe55efSEd Tanous             {
304daf36e2eSEd Tanous                 continue;
305daf36e2eSEd Tanous             }
30626f03899SShawn McCarney 
307002d39b4SEd Tanous             auto health = std::make_shared<HealthPopulate>(asyncResp);
308b49ac873SJames Feist 
30913451e39SWilly Tu             if constexpr (bmcwebEnableHealthPopulate)
31013451e39SWilly Tu             {
3116c3e9451SGeorge Liu                 dbus::utility::getAssociationEndPoints(
3126c3e9451SGeorge Liu                     path + "/all_sensors",
3135e7e2dc5SEd Tanous                     [health](const boost::system::error_code& ec2,
3146c3e9451SGeorge Liu                              const dbus::utility::MapperEndPoints& resp) {
31523a21a1cSEd Tanous                     if (ec2)
316b49ac873SJames Feist                     {
317b49ac873SJames Feist                         return; // no sensors = no failures
318b49ac873SJames Feist                     }
3191e1e598dSJonathan Doman                     health->inventory = resp;
3201e1e598dSJonathan Doman                     });
321b49ac873SJames Feist 
322b49ac873SJames Feist                 health->populate();
32313451e39SWilly Tu             }
324b49ac873SJames Feist 
32526f6976fSEd Tanous             if (connectionNames.empty())
3261abe55efSEd Tanous             {
3271c8fba97SJames Feist                 BMCWEB_LOG_ERROR << "Got 0 Connection names";
328e0d918bcSEd Tanous                 continue;
329daf36e2eSEd Tanous             }
330e0d918bcSEd Tanous 
33149c53ac9SJohnathan Mantey             asyncResp->res.jsonValue["@odata.type"] =
332523d4868SLogananth Sundararaj                 "#Chassis.v1_22_0.Chassis";
33349c53ac9SJohnathan Mantey             asyncResp->res.jsonValue["@odata.id"] =
334ef4c65b7SEd Tanous                 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
33549c53ac9SJohnathan Mantey             asyncResp->res.jsonValue["Name"] = "Chassis Collection";
33649c53ac9SJohnathan Mantey             asyncResp->res.jsonValue["ChassisType"] = "RackMount";
337cf7eba09SNan Zhou             asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
338ef4c65b7SEd Tanous                 boost::urls::format(
339ef4c65b7SEd Tanous                     "/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId);
3401476687dSEd Tanous             asyncResp->res
341cf7eba09SNan Zhou                 .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
342ef4c65b7SEd Tanous                 boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
343ef4c65b7SEd Tanous                                     chassisId);
3441476687dSEd Tanous             asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
345ef4c65b7SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices";
34649c53ac9SJohnathan Mantey 
3476c3e9451SGeorge Liu             dbus::utility::getAssociationEndPoints(
3486c3e9451SGeorge Liu                 path + "/drive",
3496c3e9451SGeorge Liu                 [asyncResp,
3506c3e9451SGeorge Liu                  chassisId](const boost::system::error_code& ec3,
3516c3e9451SGeorge Liu                             const dbus::utility::MapperEndPoints& resp) {
35292903bd4SJohn Edward Broadbent                 if (ec3 || resp.empty())
35392903bd4SJohn Edward Broadbent                 {
35492903bd4SJohn Edward Broadbent                     return; // no drives = no failures
35592903bd4SJohn Edward Broadbent                 }
35692903bd4SJohn Edward Broadbent 
35792903bd4SJohn Edward Broadbent                 nlohmann::json reference;
358ef4c65b7SEd Tanous                 reference["@odata.id"] = boost::urls::format(
359ef4c65b7SEd Tanous                     "/redfish/v1/Chassis/{}/Drives", chassisId);
36092903bd4SJohn Edward Broadbent                 asyncResp->res.jsonValue["Drives"] = std::move(reference);
36192903bd4SJohn Edward Broadbent                 });
36292903bd4SJohn Edward Broadbent 
363002d39b4SEd Tanous             const std::string& connectionName = connectionNames[0].first;
3641c8fba97SJames Feist 
36523a21a1cSEd Tanous             const std::vector<std::string>& interfaces2 =
3661c8fba97SJames Feist                 connectionNames[0].second;
3671c8fba97SJames Feist             const std::array<const char*, 2> hasIndicatorLed = {
3681c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
3690fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
3701c8fba97SJames Feist 
371476b9cc5STejas Patil             const std::string assetTagInterface =
3720fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
373523d4868SLogananth Sundararaj             const std::string replaceableInterface =
374523d4868SLogananth Sundararaj                 "xyz.openbmc_project.Inventory.Decorator.Replaceable";
375523d4868SLogananth Sundararaj             for (const auto& interface : interfaces2)
376523d4868SLogananth Sundararaj             {
377523d4868SLogananth Sundararaj                 if (interface == assetTagInterface)
378476b9cc5STejas Patil                 {
3791e1e598dSJonathan Doman                     sdbusplus::asio::getProperty<std::string>(
380002d39b4SEd Tanous                         *crow::connections::systemBus, connectionName, path,
381002d39b4SEd Tanous                         assetTagInterface, "AssetTag",
382523d4868SLogananth Sundararaj                         [asyncResp,
383523d4868SLogananth Sundararaj                          chassisId](const boost::system::error_code& ec2,
3841e1e598dSJonathan Doman                                     const std::string& property) {
3858a592810SEd Tanous                         if (ec2)
386476b9cc5STejas Patil                         {
387523d4868SLogananth Sundararaj                             BMCWEB_LOG_ERROR
388523d4868SLogananth Sundararaj                                 << "DBus response error for AssetTag: " << ec2;
389476b9cc5STejas Patil                             messages::internalError(asyncResp->res);
390476b9cc5STejas Patil                             return;
391476b9cc5STejas Patil                         }
392002d39b4SEd Tanous                         asyncResp->res.jsonValue["AssetTag"] = property;
3931e1e598dSJonathan Doman                         });
394476b9cc5STejas Patil                 }
395523d4868SLogananth Sundararaj                 else if (interface == replaceableInterface)
396523d4868SLogananth Sundararaj                 {
397523d4868SLogananth Sundararaj                     sdbusplus::asio::getProperty<bool>(
398523d4868SLogananth Sundararaj                         *crow::connections::systemBus, connectionName, path,
399523d4868SLogananth Sundararaj                         replaceableInterface, "HotPluggable",
400523d4868SLogananth Sundararaj                         [asyncResp,
401523d4868SLogananth Sundararaj                          chassisId](const boost::system::error_code& ec2,
402523d4868SLogananth Sundararaj                                     const bool property) {
403523d4868SLogananth Sundararaj                         if (ec2)
404523d4868SLogananth Sundararaj                         {
405523d4868SLogananth Sundararaj                             BMCWEB_LOG_ERROR
406523d4868SLogananth Sundararaj                                 << "DBus response error for HotPluggable: "
407523d4868SLogananth Sundararaj                                 << ec2;
408523d4868SLogananth Sundararaj                             messages::internalError(asyncResp->res);
409523d4868SLogananth Sundararaj                             return;
410523d4868SLogananth Sundararaj                         }
411523d4868SLogananth Sundararaj                         asyncResp->res.jsonValue["HotPluggable"] = property;
412523d4868SLogananth Sundararaj                         });
413523d4868SLogananth Sundararaj                 }
414523d4868SLogananth Sundararaj             }
415476b9cc5STejas Patil 
4161c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
4171c8fba97SJames Feist             {
418002d39b4SEd Tanous                 if (std::find(interfaces2.begin(), interfaces2.end(),
41923a21a1cSEd Tanous                               interface) != interfaces2.end())
4201c8fba97SJames Feist                 {
4211c8fba97SJames Feist                     getIndicatorLedState(asyncResp);
4229f8bfa7cSGunnar Mills                     getLocationIndicatorActive(asyncResp);
4231c8fba97SJames Feist                     break;
4241c8fba97SJames Feist                 }
4251c8fba97SJames Feist             }
4261c8fba97SJames Feist 
42786d89ed7SKrzysztof Grobelny             sdbusplus::asio::getAllProperties(
42886d89ed7SKrzysztof Grobelny                 *crow::connections::systemBus, connectionName, path,
42986d89ed7SKrzysztof Grobelny                 "xyz.openbmc_project.Inventory.Decorator.Asset",
4305e577bc1SWilly Tu                 [asyncResp, chassisId(std::string(chassisId)),
4315e577bc1SWilly Tu                  path](const boost::system::error_code& /*ec2*/,
432cf7eba09SNan Zhou                        const dbus::utility::DBusPropertiesMap& propertiesList) {
43386d89ed7SKrzysztof Grobelny                 const std::string* partNumber = nullptr;
43486d89ed7SKrzysztof Grobelny                 const std::string* serialNumber = nullptr;
43586d89ed7SKrzysztof Grobelny                 const std::string* manufacturer = nullptr;
43686d89ed7SKrzysztof Grobelny                 const std::string* model = nullptr;
43786d89ed7SKrzysztof Grobelny                 const std::string* sparePartNumber = nullptr;
43886d89ed7SKrzysztof Grobelny 
43986d89ed7SKrzysztof Grobelny                 const bool success = sdbusplus::unpackPropertiesNoThrow(
44086d89ed7SKrzysztof Grobelny                     dbus_utils::UnpackErrorPrinter(), propertiesList,
44186d89ed7SKrzysztof Grobelny                     "PartNumber", partNumber, "SerialNumber", serialNumber,
44286d89ed7SKrzysztof Grobelny                     "Manufacturer", manufacturer, "Model", model,
44386d89ed7SKrzysztof Grobelny                     "SparePartNumber", sparePartNumber);
44486d89ed7SKrzysztof Grobelny 
44586d89ed7SKrzysztof Grobelny                 if (!success)
4461abe55efSEd Tanous                 {
447002d39b4SEd Tanous                     messages::internalError(asyncResp->res);
448caa11f7aSAlpana Kumari                     return;
449daf36e2eSEd Tanous                 }
45086d89ed7SKrzysztof Grobelny 
45186d89ed7SKrzysztof Grobelny                 if (partNumber != nullptr)
45286d89ed7SKrzysztof Grobelny                 {
45386d89ed7SKrzysztof Grobelny                     asyncResp->res.jsonValue["PartNumber"] = *partNumber;
45486d89ed7SKrzysztof Grobelny                 }
45586d89ed7SKrzysztof Grobelny 
45686d89ed7SKrzysztof Grobelny                 if (serialNumber != nullptr)
45786d89ed7SKrzysztof Grobelny                 {
45886d89ed7SKrzysztof Grobelny                     asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
45986d89ed7SKrzysztof Grobelny                 }
46086d89ed7SKrzysztof Grobelny 
46186d89ed7SKrzysztof Grobelny                 if (manufacturer != nullptr)
46286d89ed7SKrzysztof Grobelny                 {
46386d89ed7SKrzysztof Grobelny                     asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
46486d89ed7SKrzysztof Grobelny                 }
46586d89ed7SKrzysztof Grobelny 
46686d89ed7SKrzysztof Grobelny                 if (model != nullptr)
46786d89ed7SKrzysztof Grobelny                 {
46886d89ed7SKrzysztof Grobelny                     asyncResp->res.jsonValue["Model"] = *model;
46986d89ed7SKrzysztof Grobelny                 }
47086d89ed7SKrzysztof Grobelny 
471caa11f7aSAlpana Kumari                 // SparePartNumber is optional on D-Bus
472caa11f7aSAlpana Kumari                 // so skip if it is empty
47386d89ed7SKrzysztof Grobelny                 if (sparePartNumber != nullptr && !sparePartNumber->empty())
474caa11f7aSAlpana Kumari                 {
47586d89ed7SKrzysztof Grobelny                     asyncResp->res.jsonValue["SparePartNumber"] =
47686d89ed7SKrzysztof Grobelny                         *sparePartNumber;
477caa11f7aSAlpana Kumari                 }
47886d89ed7SKrzysztof Grobelny 
47962d5e2e4SEd Tanous                 asyncResp->res.jsonValue["Name"] = chassisId;
48062d5e2e4SEd Tanous                 asyncResp->res.jsonValue["Id"] = chassisId;
4810256b694Szhanghch05 #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
482002d39b4SEd Tanous                 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
483ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}/Thermal",
484ef4c65b7SEd Tanous                                         chassisId);
4852474adfaSEd Tanous                 // Power object
4861476687dSEd Tanous                 asyncResp->res.jsonValue["Power"]["@odata.id"] =
487ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}/Power",
488ef4c65b7SEd Tanous                                         chassisId);
4890256b694Szhanghch05 #endif
4902973963eSXiaochao Ma #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
4912973963eSXiaochao Ma                 asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
492ef4c65b7SEd Tanous                     boost::urls::format(
493ef4c65b7SEd Tanous                         "/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId);
49477b36437SChicago Duan                 asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
495ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
496ef4c65b7SEd Tanous                                         chassisId);
4974ca3ec3cSAlbert Zhang                 asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
498ef4c65b7SEd Tanous                     boost::urls::format(
499ef4c65b7SEd Tanous                         "/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId);
5002973963eSXiaochao Ma #endif
50195a3ecadSAnthony Wilson                 // SensorCollection
502002d39b4SEd Tanous                 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
503ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}/Sensors",
504ef4c65b7SEd Tanous                                         chassisId);
505002d39b4SEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
5061476687dSEd Tanous 
5071476687dSEd Tanous                 nlohmann::json::array_t computerSystems;
5081476687dSEd Tanous                 nlohmann::json::object_t system;
509002d39b4SEd Tanous                 system["@odata.id"] = "/redfish/v1/Systems/system";
510ad539545SPatrick Williams                 computerSystems.emplace_back(std::move(system));
511002d39b4SEd Tanous                 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
5121476687dSEd Tanous                     std::move(computerSystems);
5131476687dSEd Tanous 
5141476687dSEd Tanous                 nlohmann::json::array_t managedBy;
5151476687dSEd Tanous                 nlohmann::json::object_t manager;
516002d39b4SEd Tanous                 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
517ad539545SPatrick Williams                 managedBy.emplace_back(std::move(manager));
5187e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
5191476687dSEd Tanous                     std::move(managedBy);
520beeca0aeSGunnar Mills                 getChassisState(asyncResp);
5215e577bc1SWilly Tu                 getStorageLink(asyncResp, path);
52286d89ed7SKrzysztof Grobelny                 });
5232c37b4b0SSharad Yadav 
524308f70c7SWilly Tu             for (const auto& interface : interfaces2)
5252c37b4b0SSharad Yadav             {
526308f70c7SWilly Tu                 if (interface == "xyz.openbmc_project.Common.UUID")
5272c37b4b0SSharad Yadav                 {
528308f70c7SWilly Tu                     getChassisUUID(asyncResp, connectionName, path);
5292c37b4b0SSharad Yadav                 }
530cf7eba09SNan Zhou                 else if (interface ==
5310fda0f12SGeorge Liu                          "xyz.openbmc_project.Inventory.Decorator.LocationCode")
5322c37b4b0SSharad Yadav                 {
533002d39b4SEd Tanous                     getChassisLocationCode(asyncResp, connectionName, path);
5342c37b4b0SSharad Yadav                 }
5352c37b4b0SSharad Yadav             }
5362c37b4b0SSharad Yadav 
537daf36e2eSEd Tanous             return;
538daf36e2eSEd Tanous         }
539e0d918bcSEd Tanous 
540daf36e2eSEd Tanous         // Couldn't find an object with that name.  return an error
541d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
542e99073f5SGeorge Liu         });
543c181942fSQiang XU 
544c181942fSQiang XU     getPhysicalSecurityData(asyncResp);
545cf7eba09SNan Zhou }
5461c8fba97SJames Feist 
547cf7eba09SNan Zhou inline void
548cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
5497e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
550cf7eba09SNan Zhou                        const std::string& param)
551cf7eba09SNan Zhou {
5523ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
55345ca1b86SEd Tanous     {
55445ca1b86SEd Tanous         return;
55545ca1b86SEd Tanous     }
5569f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
5571c8fba97SJames Feist     std::optional<std::string> indicatorLed;
5581c8fba97SJames Feist 
5597e860f15SJohn Edward Broadbent     if (param.empty())
5601c8fba97SJames Feist     {
5611c8fba97SJames Feist         return;
5621c8fba97SJames Feist     }
5631c8fba97SJames Feist 
56415ed6780SWilly Tu     if (!json_util::readJsonPatch(
5657e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
5667e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
5671c8fba97SJames Feist     {
5681c8fba97SJames Feist         return;
5691c8fba97SJames Feist     }
5701c8fba97SJames Feist 
5719f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
5729f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
5731c8fba97SJames Feist     {
5741c8fba97SJames Feist         return; // delete this when we support more patch properties
5751c8fba97SJames Feist     }
576d6aa0093SGunnar Mills     if (indicatorLed)
577d6aa0093SGunnar Mills     {
5787e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
5797e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
5800fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
581d6aa0093SGunnar Mills     }
5821c8fba97SJames Feist 
583e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
5841c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
5851c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
5861c8fba97SJames Feist 
5877e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
5881c8fba97SJames Feist 
589e99073f5SGeorge Liu     dbus::utility::getSubTree(
590e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
591cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
5925e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
593b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
5941c8fba97SJames Feist         if (ec)
5951c8fba97SJames Feist         {
59651dab2a7SAndrew Geissler             BMCWEB_LOG_ERROR << "DBUS response error " << ec;
5971c8fba97SJames Feist             messages::internalError(asyncResp->res);
5981c8fba97SJames Feist             return;
5991c8fba97SJames Feist         }
6001c8fba97SJames Feist 
6011c8fba97SJames Feist         // Iterate over all retrieved ObjectPaths.
602cf7eba09SNan Zhou         for (const std::pair<
603cf7eba09SNan Zhou                  std::string,
604cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
6051214b7e7SGunnar Mills                  object : subtree)
6061c8fba97SJames Feist         {
6071c8fba97SJames Feist             const std::string& path = object.first;
608cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
6091214b7e7SGunnar Mills                 connectionNames = object.second;
6101c8fba97SJames Feist 
611997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
612997093ebSGeorge Liu             if (objPath.filename() != chassisId)
6131c8fba97SJames Feist             {
6141c8fba97SJames Feist                 continue;
6151c8fba97SJames Feist             }
6161c8fba97SJames Feist 
61726f6976fSEd Tanous             if (connectionNames.empty())
6181c8fba97SJames Feist             {
6191c8fba97SJames Feist                 BMCWEB_LOG_ERROR << "Got 0 Connection names";
6201c8fba97SJames Feist                 continue;
6211c8fba97SJames Feist             }
6221c8fba97SJames Feist 
62323a21a1cSEd Tanous             const std::vector<std::string>& interfaces3 =
6241c8fba97SJames Feist                 connectionNames[0].second;
6251c8fba97SJames Feist 
6261c8fba97SJames Feist             const std::array<const char*, 2> hasIndicatorLed = {
6271c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
6280fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
6291c8fba97SJames Feist             bool indicatorChassis = false;
6301c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
6311c8fba97SJames Feist             {
632002d39b4SEd Tanous                 if (std::find(interfaces3.begin(), interfaces3.end(),
63323a21a1cSEd Tanous                               interface) != interfaces3.end())
6341c8fba97SJames Feist                 {
6351c8fba97SJames Feist                     indicatorChassis = true;
6361c8fba97SJames Feist                     break;
6371c8fba97SJames Feist                 }
6381c8fba97SJames Feist             }
6399f8bfa7cSGunnar Mills             if (locationIndicatorActive)
6409f8bfa7cSGunnar Mills             {
6419f8bfa7cSGunnar Mills                 if (indicatorChassis)
6429f8bfa7cSGunnar Mills                 {
643002d39b4SEd Tanous                     setLocationIndicatorActive(asyncResp,
644002d39b4SEd Tanous                                                *locationIndicatorActive);
6459f8bfa7cSGunnar Mills                 }
6469f8bfa7cSGunnar Mills                 else
6479f8bfa7cSGunnar Mills                 {
648002d39b4SEd Tanous                     messages::propertyUnknown(asyncResp->res,
649002d39b4SEd Tanous                                               "LocationIndicatorActive");
6509f8bfa7cSGunnar Mills                 }
6519f8bfa7cSGunnar Mills             }
6529f8bfa7cSGunnar Mills             if (indicatorLed)
6539f8bfa7cSGunnar Mills             {
6541c8fba97SJames Feist                 if (indicatorChassis)
6551c8fba97SJames Feist                 {
656f23b7296SEd Tanous                     setIndicatorLedState(asyncResp, *indicatorLed);
6571c8fba97SJames Feist                 }
6581c8fba97SJames Feist                 else
6591c8fba97SJames Feist                 {
660cf7eba09SNan Zhou                     messages::propertyUnknown(asyncResp->res, "IndicatorLED");
6611c8fba97SJames Feist                 }
6621c8fba97SJames Feist             }
6631c8fba97SJames Feist             return;
6641c8fba97SJames Feist         }
6651c8fba97SJames Feist 
666d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
667e99073f5SGeorge Liu         });
668cf7eba09SNan Zhou }
669cf7eba09SNan Zhou 
670cf7eba09SNan Zhou /**
671cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
672cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
673cf7eba09SNan Zhou  */
674cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
675cf7eba09SNan Zhou {
676cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
677cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
678cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
679cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
680cf7eba09SNan Zhou 
681cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
682cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
683cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
684cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
6851c8fba97SJames Feist }
686dd99e04bSP.K. Lee 
687fc903b3dSAndrew Geissler /**
688fc903b3dSAndrew Geissler  * Handle error responses from d-bus for chassis power cycles
689fc903b3dSAndrew Geissler  */
690fc903b3dSAndrew Geissler inline void handleChassisPowerCycleError(const boost::system::error_code& ec,
691fc903b3dSAndrew Geissler                                          const sdbusplus::message_t& eMsg,
692fc903b3dSAndrew Geissler                                          crow::Response& res)
693fc903b3dSAndrew Geissler {
694fc903b3dSAndrew Geissler     if (eMsg.get_error() == nullptr)
695fc903b3dSAndrew Geissler     {
696fc903b3dSAndrew Geissler         BMCWEB_LOG_ERROR << "D-Bus response error: " << ec;
697fc903b3dSAndrew Geissler         messages::internalError(res);
698fc903b3dSAndrew Geissler         return;
699fc903b3dSAndrew Geissler     }
700fc903b3dSAndrew Geissler     std::string_view errorMessage = eMsg.get_error()->name;
701fc903b3dSAndrew Geissler 
702fc903b3dSAndrew Geissler     // If operation failed due to BMC not being in Ready state, tell
703fc903b3dSAndrew Geissler     // user to retry in a bit
704fc903b3dSAndrew Geissler     if (errorMessage ==
705fc903b3dSAndrew Geissler         std::string_view("xyz.openbmc_project.State.Chassis.Error.BMCNotReady"))
706fc903b3dSAndrew Geissler     {
707fc903b3dSAndrew Geissler         BMCWEB_LOG_DEBUG << "BMC not ready, operation not allowed right now";
708fc903b3dSAndrew Geissler         messages::serviceTemporarilyUnavailable(res, "10");
709fc903b3dSAndrew Geissler         return;
710fc903b3dSAndrew Geissler     }
711fc903b3dSAndrew Geissler 
712fc903b3dSAndrew Geissler     BMCWEB_LOG_ERROR << "Chassis Power Cycle fail " << ec
713fc903b3dSAndrew Geissler                      << " sdbusplus:" << errorMessage;
714fc903b3dSAndrew Geissler     messages::internalError(res);
715fc903b3dSAndrew Geissler }
716fc903b3dSAndrew Geissler 
7178d1b46d7Szhanghch05 inline void
7188d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
719dd99e04bSP.K. Lee {
7207a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
721c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
722c3b3c92aSVijay Khemka 
723c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
7247a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
7257a1dbc48SGeorge Liu         "/", 0, interfaces,
726b9d36b47SEd Tanous         [asyncResp](
7277a1dbc48SGeorge Liu             const boost::system::error_code& ec,
728b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
729c3b3c92aSVijay Khemka         if (ec)
730c3b3c92aSVijay Khemka         {
73151dab2a7SAndrew Geissler             BMCWEB_LOG_ERROR << "[mapper] Bad D-Bus request error: " << ec;
732c3b3c92aSVijay Khemka             messages::internalError(asyncResp->res);
733c3b3c92aSVijay Khemka             return;
734c3b3c92aSVijay Khemka         }
735c3b3c92aSVijay Khemka 
736dd99e04bSP.K. Lee         const char* processName = "xyz.openbmc_project.State.Chassis";
737dd99e04bSP.K. Lee         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
738dd99e04bSP.K. Lee         const char* destProperty = "RequestedPowerTransition";
739dd99e04bSP.K. Lee         const std::string propertyValue =
740dd99e04bSP.K. Lee             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
741002d39b4SEd Tanous         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
742c3b3c92aSVijay Khemka 
743c3b3c92aSVijay Khemka         /* Look for system reset chassis path */
744002d39b4SEd Tanous         if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
745002d39b4SEd Tanous             chassisList.end())
746c3b3c92aSVijay Khemka         {
747c3b3c92aSVijay Khemka             /* We prefer to reset the full chassis_system, but if it doesn't
748c3b3c92aSVijay Khemka              * exist on some platforms, fall back to a host-only power reset
749c3b3c92aSVijay Khemka              */
750c3b3c92aSVijay Khemka             objectPath = "/xyz/openbmc_project/state/chassis0";
751c3b3c92aSVijay Khemka         }
752dd99e04bSP.K. Lee 
753*9ae226faSGeorge Liu         sdbusplus::asio::setProperty(
754*9ae226faSGeorge Liu             *crow::connections::systemBus, processName, objectPath,
755*9ae226faSGeorge Liu             interfaceName, destProperty, propertyValue,
756fc903b3dSAndrew Geissler             [asyncResp](const boost::system::error_code& ec2,
757fc903b3dSAndrew Geissler                         sdbusplus::message_t& sdbusErrMsg) {
758dd99e04bSP.K. Lee             // Use "Set" method to set the property value.
7598a592810SEd Tanous             if (ec2)
760dd99e04bSP.K. Lee             {
761fc903b3dSAndrew Geissler                 handleChassisPowerCycleError(ec2, sdbusErrMsg, asyncResp->res);
762fc903b3dSAndrew Geissler 
763dd99e04bSP.K. Lee                 return;
764dd99e04bSP.K. Lee             }
765dd99e04bSP.K. Lee 
766dd99e04bSP.K. Lee             messages::success(asyncResp->res);
767*9ae226faSGeorge Liu             });
7687a1dbc48SGeorge Liu         });
769dd99e04bSP.K. Lee }
770dd99e04bSP.K. Lee 
771cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
772cf7eba09SNan Zhou     App& app, const crow::Request& req,
7737e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
774cf7eba09SNan Zhou     const std::string& /*chassisId*/)
775cf7eba09SNan Zhou {
7763ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
77745ca1b86SEd Tanous     {
77845ca1b86SEd Tanous         return;
77945ca1b86SEd Tanous     }
780dd99e04bSP.K. Lee     BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
781dd99e04bSP.K. Lee 
782dd99e04bSP.K. Lee     std::string resetType;
783dd99e04bSP.K. Lee 
784cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
785dd99e04bSP.K. Lee     {
786dd99e04bSP.K. Lee         return;
787dd99e04bSP.K. Lee     }
788dd99e04bSP.K. Lee 
789dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
790dd99e04bSP.K. Lee     {
791dd99e04bSP.K. Lee         BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
792dd99e04bSP.K. Lee                          << resetType;
793002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
794002d39b4SEd Tanous                                               "ResetType");
795dd99e04bSP.K. Lee 
796dd99e04bSP.K. Lee         return;
797dd99e04bSP.K. Lee     }
798dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
799dd99e04bSP.K. Lee }
8001cb1a9e6SAppaRao Puli 
8011cb1a9e6SAppaRao Puli /**
802cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
803cf7eba09SNan Zhou  * action.
804cf7eba09SNan Zhou  * Function handles POST method request.
805cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8061cb1a9e6SAppaRao Puli  */
807cf7eba09SNan Zhou 
808cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8091cb1a9e6SAppaRao Puli {
810cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
811cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
812cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
813cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
814cf7eba09SNan Zhou }
815cf7eba09SNan Zhou 
816cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
817cf7eba09SNan Zhou     App& app, const crow::Request& req,
8187e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819cf7eba09SNan Zhou     const std::string& chassisId)
820cf7eba09SNan Zhou {
8213ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
8221cb1a9e6SAppaRao Puli     {
82345ca1b86SEd Tanous         return;
82445ca1b86SEd Tanous     }
825cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
826ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
827ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
8281476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
8291476687dSEd Tanous 
8301476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
8315b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
8325b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
8335b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
8345b9e95a1SNan Zhou     parameter["Required"] = true;
8355b9e95a1SNan Zhou     parameter["DataType"] = "String";
8361476687dSEd Tanous     nlohmann::json::array_t allowed;
837ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
8385b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
839ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
8405b9e95a1SNan Zhou 
8411476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
842cf7eba09SNan Zhou }
843cf7eba09SNan Zhou 
844cf7eba09SNan Zhou /**
845cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
846cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
847cf7eba09SNan Zhou  */
848cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
849cf7eba09SNan Zhou {
850cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
851cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
852cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
853cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
8541cb1a9e6SAppaRao Puli }
8551cb1a9e6SAppaRao Puli 
856e37f8451SRapkiewicz, Pawel } // namespace redfish
857