xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision afc474aef028555fc0a6deb425bdad86f0a34db6)
19c310685SBorawski.Lukasz /*
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.
159c310685SBorawski.Lukasz */
169c310685SBorawski.Lukasz #pragma once
179c310685SBorawski.Lukasz 
1813451e39SWilly Tu #include "bmcweb_config.h"
1913451e39SWilly Tu 
20a51fc2d2SSui Chen #include "app.hpp"
21a51fc2d2SSui Chen #include "dbus_utility.hpp"
22539d8c6bSEd Tanous #include "generated/enums/action_info.hpp"
23539d8c6bSEd Tanous #include "generated/enums/manager.hpp"
24539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
25a51fc2d2SSui Chen #include "query.hpp"
26c5d03ff4SJennifer Lee #include "redfish_util.hpp"
27a51fc2d2SSui Chen #include "registries/privilege_registry.hpp"
28fac6e53bSKrzysztof Grobelny #include "utils/dbus_utils.hpp"
293ccb3adbSEd Tanous #include "utils/json_utils.hpp"
30a51fc2d2SSui Chen #include "utils/sw_utils.hpp"
31a51fc2d2SSui Chen #include "utils/systemd_utils.hpp"
322b82937eSEd Tanous #include "utils/time_utils.hpp"
339c310685SBorawski.Lukasz 
34e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
35ef4c65b7SEd Tanous #include <boost/url/format.hpp>
36fac6e53bSKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
37fac6e53bSKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
381214b7e7SGunnar Mills 
39a170f275SEd Tanous #include <algorithm>
40e99073f5SGeorge Liu #include <array>
414bfefa74SGunnar Mills #include <cstdint>
421214b7e7SGunnar Mills #include <memory>
439970e93fSKonstantin Aladyshev #include <optional>
443544d2a7SEd Tanous #include <ranges>
451214b7e7SGunnar Mills #include <sstream>
469970e93fSKonstantin Aladyshev #include <string>
47e99073f5SGeorge Liu #include <string_view>
48abf2add6SEd Tanous #include <variant>
495b4aa86bSJames Feist 
501abe55efSEd Tanous namespace redfish
511abe55efSEd Tanous {
52ed5befbdSJennifer Lee 
53ed5befbdSJennifer Lee /**
542a5c4407SGunnar Mills  * Function reboots the BMC.
552a5c4407SGunnar Mills  *
562a5c4407SGunnar Mills  * @param[in] asyncResp - Shared pointer for completing asynchronous calls
57ed5befbdSJennifer Lee  */
588d1b46d7Szhanghch05 inline void
598d1b46d7Szhanghch05     doBMCGracefulRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
60ed5befbdSJennifer Lee {
61ed5befbdSJennifer Lee     const char* processName = "xyz.openbmc_project.State.BMC";
62ed5befbdSJennifer Lee     const char* objectPath = "/xyz/openbmc_project/state/bmc0";
63ed5befbdSJennifer Lee     const char* interfaceName = "xyz.openbmc_project.State.BMC";
64ed5befbdSJennifer Lee     const std::string& propertyValue =
65ed5befbdSJennifer Lee         "xyz.openbmc_project.State.BMC.Transition.Reboot";
66ed5befbdSJennifer Lee     const char* destProperty = "RequestedBMCTransition";
67ed5befbdSJennifer Lee 
68ed5befbdSJennifer Lee     // Create the D-Bus variant for D-Bus call.
699ae226faSGeorge Liu     sdbusplus::asio::setProperty(
709ae226faSGeorge Liu         *crow::connections::systemBus, processName, objectPath, interfaceName,
719ae226faSGeorge Liu         destProperty, propertyValue,
725e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec) {
73ed5befbdSJennifer Lee             // Use "Set" method to set the property value.
74ed5befbdSJennifer Lee             if (ec)
75ed5befbdSJennifer Lee             {
7662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
77ed5befbdSJennifer Lee                 messages::internalError(asyncResp->res);
78ed5befbdSJennifer Lee                 return;
79ed5befbdSJennifer Lee             }
80ed5befbdSJennifer Lee 
81ed5befbdSJennifer Lee             messages::success(asyncResp->res);
829ae226faSGeorge Liu         });
83ed5befbdSJennifer Lee }
842a5c4407SGunnar Mills 
858d1b46d7Szhanghch05 inline void
868d1b46d7Szhanghch05     doBMCForceRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
87f92af389SJayaprakash Mutyala {
88f92af389SJayaprakash Mutyala     const char* processName = "xyz.openbmc_project.State.BMC";
89f92af389SJayaprakash Mutyala     const char* objectPath = "/xyz/openbmc_project/state/bmc0";
90f92af389SJayaprakash Mutyala     const char* interfaceName = "xyz.openbmc_project.State.BMC";
91f92af389SJayaprakash Mutyala     const std::string& propertyValue =
92f92af389SJayaprakash Mutyala         "xyz.openbmc_project.State.BMC.Transition.HardReboot";
93f92af389SJayaprakash Mutyala     const char* destProperty = "RequestedBMCTransition";
94f92af389SJayaprakash Mutyala 
95f92af389SJayaprakash Mutyala     // Create the D-Bus variant for D-Bus call.
969ae226faSGeorge Liu     sdbusplus::asio::setProperty(
979ae226faSGeorge Liu         *crow::connections::systemBus, processName, objectPath, interfaceName,
989ae226faSGeorge Liu         destProperty, propertyValue,
995e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec) {
100f92af389SJayaprakash Mutyala             // Use "Set" method to set the property value.
101f92af389SJayaprakash Mutyala             if (ec)
102f92af389SJayaprakash Mutyala             {
10362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
104f92af389SJayaprakash Mutyala                 messages::internalError(asyncResp->res);
105f92af389SJayaprakash Mutyala                 return;
106f92af389SJayaprakash Mutyala             }
107f92af389SJayaprakash Mutyala 
108f92af389SJayaprakash Mutyala             messages::success(asyncResp->res);
1099ae226faSGeorge Liu         });
110f92af389SJayaprakash Mutyala }
111f92af389SJayaprakash Mutyala 
1122a5c4407SGunnar Mills /**
1132a5c4407SGunnar Mills  * ManagerResetAction class supports the POST method for the Reset (reboot)
1142a5c4407SGunnar Mills  * action.
1152a5c4407SGunnar Mills  */
1167e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetAction(App& app)
1172a5c4407SGunnar Mills {
1182a5c4407SGunnar Mills     /**
1192a5c4407SGunnar Mills      * Function handles POST method request.
1202a5c4407SGunnar Mills      * Analyzes POST body before sending Reset (Reboot) request data to D-Bus.
121f92af389SJayaprakash Mutyala      * OpenBMC supports ResetType "GracefulRestart" and "ForceRestart".
1222a5c4407SGunnar Mills      */
1237e860f15SJohn Edward Broadbent 
124253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Actions/Manager.Reset/")
125ed398213SEd Tanous         .privileges(redfish::privileges::postManager)
1267e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
12745ca1b86SEd Tanous             [&app](const crow::Request& req,
128253f11b8SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
129253f11b8SEd Tanous                    const std::string& managerId) {
1303ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
13145ca1b86SEd Tanous                 {
13245ca1b86SEd Tanous                     return;
13345ca1b86SEd Tanous                 }
134253f11b8SEd Tanous                 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
135253f11b8SEd Tanous                 {
136bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Manager",
137bd79bce8SPatrick Williams                                                managerId);
138253f11b8SEd Tanous                     return;
139253f11b8SEd Tanous                 }
140253f11b8SEd Tanous 
14162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Post Manager Reset.");
1422a5c4407SGunnar Mills 
1432a5c4407SGunnar Mills                 std::string resetType;
1442a5c4407SGunnar Mills 
14515ed6780SWilly Tu                 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
1467e860f15SJohn Edward Broadbent                                                resetType))
1472a5c4407SGunnar Mills                 {
1482a5c4407SGunnar Mills                     return;
1492a5c4407SGunnar Mills                 }
1502a5c4407SGunnar Mills 
151f92af389SJayaprakash Mutyala                 if (resetType == "GracefulRestart")
152f92af389SJayaprakash Mutyala                 {
15362598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
154f92af389SJayaprakash Mutyala                     doBMCGracefulRestart(asyncResp);
155f92af389SJayaprakash Mutyala                     return;
156f92af389SJayaprakash Mutyala                 }
1573174e4dfSEd Tanous                 if (resetType == "ForceRestart")
158f92af389SJayaprakash Mutyala                 {
15962598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
160f92af389SJayaprakash Mutyala                     doBMCForceRestart(asyncResp);
161f92af389SJayaprakash Mutyala                     return;
162f92af389SJayaprakash Mutyala                 }
163bd79bce8SPatrick Williams                 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
164bd79bce8SPatrick Williams                                  resetType);
1652a5c4407SGunnar Mills                 messages::actionParameterNotSupported(asyncResp->res, resetType,
1662a5c4407SGunnar Mills                                                       "ResetType");
1672a5c4407SGunnar Mills 
1682a5c4407SGunnar Mills                 return;
1697e860f15SJohn Edward Broadbent             });
1702a5c4407SGunnar Mills }
171ed5befbdSJennifer Lee 
1723e40fc74SGunnar Mills /**
1733e40fc74SGunnar Mills  * ManagerResetToDefaultsAction class supports POST method for factory reset
1743e40fc74SGunnar Mills  * action.
1753e40fc74SGunnar Mills  */
1767e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetToDefaultsAction(App& app)
1773e40fc74SGunnar Mills {
1783e40fc74SGunnar Mills     /**
1793e40fc74SGunnar Mills      * Function handles ResetToDefaults POST method request.
1803e40fc74SGunnar Mills      *
1813e40fc74SGunnar Mills      * Analyzes POST body message and factory resets BMC by calling
1823e40fc74SGunnar Mills      * BMC code updater factory reset followed by a BMC reboot.
1833e40fc74SGunnar Mills      *
1843e40fc74SGunnar Mills      * BMC code updater factory reset wipes the whole BMC read-write
1853e40fc74SGunnar Mills      * filesystem which includes things like the network settings.
1863e40fc74SGunnar Mills      *
1873e40fc74SGunnar Mills      * OpenBMC only supports ResetToDefaultsType "ResetAll".
1883e40fc74SGunnar Mills      */
1897e860f15SJohn Edward Broadbent 
1907e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
191253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Actions/Manager.ResetToDefaults/")
192ed398213SEd Tanous         .privileges(redfish::privileges::postManager)
193bd79bce8SPatrick Williams         .methods(
194bd79bce8SPatrick Williams             boost::beast::http::verb::
195bd79bce8SPatrick Williams                 post)([&app](
196bd79bce8SPatrick Williams                           const crow::Request& req,
197253f11b8SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
198253f11b8SEd Tanous                           const std::string& managerId) {
1993ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
20045ca1b86SEd Tanous             {
20145ca1b86SEd Tanous                 return;
20245ca1b86SEd Tanous             }
203253f11b8SEd Tanous 
204253f11b8SEd Tanous             if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
205253f11b8SEd Tanous             {
206bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Manager",
207bd79bce8SPatrick Williams                                            managerId);
208253f11b8SEd Tanous                 return;
209253f11b8SEd Tanous             }
210253f11b8SEd Tanous 
21162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Post ResetToDefaults.");
2123e40fc74SGunnar Mills 
2139970e93fSKonstantin Aladyshev             std::optional<std::string> resetType;
2149970e93fSKonstantin Aladyshev             std::optional<std::string> resetToDefaultsType;
2153e40fc74SGunnar Mills 
216*afc474aeSMyung Bae             if (!json_util::readJsonAction( //
217*afc474aeSMyung Bae                     req, asyncResp->res, //
218*afc474aeSMyung Bae                     "ResetToDefaultsType", resetToDefaultsType, //
219*afc474aeSMyung Bae                     "ResetType", resetType //
220*afc474aeSMyung Bae                     ))
2213e40fc74SGunnar Mills             {
2229970e93fSKonstantin Aladyshev                 BMCWEB_LOG_DEBUG("Missing property ResetType.");
2233e40fc74SGunnar Mills 
224bd79bce8SPatrick Williams                 messages::actionParameterMissing(
225bd79bce8SPatrick Williams                     asyncResp->res, "ResetToDefaults", "ResetType");
2263e40fc74SGunnar Mills                 return;
2273e40fc74SGunnar Mills             }
2283e40fc74SGunnar Mills 
2299970e93fSKonstantin Aladyshev             if (resetToDefaultsType && !resetType)
2309970e93fSKonstantin Aladyshev             {
2319970e93fSKonstantin Aladyshev                 BMCWEB_LOG_WARNING(
2329970e93fSKonstantin Aladyshev                     "Using deprecated ResetToDefaultsType, should be ResetType."
2339970e93fSKonstantin Aladyshev                     "Support for the ResetToDefaultsType will be dropped in 2Q24");
2349970e93fSKonstantin Aladyshev                 resetType = resetToDefaultsType;
2359970e93fSKonstantin Aladyshev             }
2369970e93fSKonstantin Aladyshev 
2373e40fc74SGunnar Mills             if (resetType != "ResetAll")
2383e40fc74SGunnar Mills             {
2399970e93fSKonstantin Aladyshev                 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
2409970e93fSKonstantin Aladyshev                                  *resetType);
241bd79bce8SPatrick Williams                 messages::actionParameterNotSupported(asyncResp->res,
242bd79bce8SPatrick Williams                                                       *resetType, "ResetType");
2433e40fc74SGunnar Mills                 return;
2443e40fc74SGunnar Mills             }
2453e40fc74SGunnar Mills 
2463e40fc74SGunnar Mills             crow::connections::systemBus->async_method_call(
2475e7e2dc5SEd Tanous                 [asyncResp](const boost::system::error_code& ec) {
2483e40fc74SGunnar Mills                     if (ec)
2493e40fc74SGunnar Mills                     {
25062598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec);
2513e40fc74SGunnar Mills                         messages::internalError(asyncResp->res);
2523e40fc74SGunnar Mills                         return;
2533e40fc74SGunnar Mills                     }
2543e40fc74SGunnar Mills                     // Factory Reset doesn't actually happen until a reboot
2553e40fc74SGunnar Mills                     // Can't erase what the BMC is running on
2563e40fc74SGunnar Mills                     doBMCGracefulRestart(asyncResp);
2573e40fc74SGunnar Mills                 },
2583e40fc74SGunnar Mills                 "xyz.openbmc_project.Software.BMC.Updater",
2593e40fc74SGunnar Mills                 "/xyz/openbmc_project/software",
2603e40fc74SGunnar Mills                 "xyz.openbmc_project.Common.FactoryReset", "Reset");
2617e860f15SJohn Edward Broadbent         });
2623e40fc74SGunnar Mills }
2633e40fc74SGunnar Mills 
2641cb1a9e6SAppaRao Puli /**
2651cb1a9e6SAppaRao Puli  * ManagerResetActionInfo derived class for delivering Manager
2661cb1a9e6SAppaRao Puli  * ResetType AllowableValues using ResetInfo schema.
2671cb1a9e6SAppaRao Puli  */
2687e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetActionInfo(App& app)
2691cb1a9e6SAppaRao Puli {
2701cb1a9e6SAppaRao Puli     /**
2711cb1a9e6SAppaRao Puli      * Functions triggers appropriate requests on DBus
2721cb1a9e6SAppaRao Puli      */
2737e860f15SJohn Edward Broadbent 
274253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/")
275ed398213SEd Tanous         .privileges(redfish::privileges::getActionInfo)
2767e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
27745ca1b86SEd Tanous             [&app](const crow::Request& req,
278253f11b8SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
279253f11b8SEd Tanous                    const std::string& managerId) {
2803ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
28145ca1b86SEd Tanous                 {
28245ca1b86SEd Tanous                     return;
28345ca1b86SEd Tanous                 }
2841476687dSEd Tanous 
285253f11b8SEd Tanous                 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
286253f11b8SEd Tanous                 {
287bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Manager",
288bd79bce8SPatrick Williams                                                managerId);
289253f11b8SEd Tanous                     return;
290253f11b8SEd Tanous                 }
291253f11b8SEd Tanous 
2921476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2931476687dSEd Tanous                     "#ActionInfo.v1_1_2.ActionInfo";
294bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
295bd79bce8SPatrick Williams                     "/redfish/v1/Managers/{}/ResetActionInfo",
296253f11b8SEd Tanous                     BMCWEB_REDFISH_MANAGER_URI_NAME);
2971476687dSEd Tanous                 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
2981476687dSEd Tanous                 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
2991476687dSEd Tanous                 nlohmann::json::object_t parameter;
3001476687dSEd Tanous                 parameter["Name"] = "ResetType";
3011476687dSEd Tanous                 parameter["Required"] = true;
302539d8c6bSEd Tanous                 parameter["DataType"] = action_info::ParameterTypes::String;
3031476687dSEd Tanous 
3041476687dSEd Tanous                 nlohmann::json::array_t allowableValues;
305ad539545SPatrick Williams                 allowableValues.emplace_back("GracefulRestart");
306ad539545SPatrick Williams                 allowableValues.emplace_back("ForceRestart");
3071476687dSEd Tanous                 parameter["AllowableValues"] = std::move(allowableValues);
3081476687dSEd Tanous 
3091476687dSEd Tanous                 nlohmann::json::array_t parameters;
310ad539545SPatrick Williams                 parameters.emplace_back(std::move(parameter));
3111476687dSEd Tanous 
3121476687dSEd Tanous                 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3137e860f15SJohn Edward Broadbent             });
3141cb1a9e6SAppaRao Puli }
3151cb1a9e6SAppaRao Puli 
3165b4aa86bSJames Feist static constexpr const char* objectManagerIface =
3175b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
3185b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
3195b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
3205b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
3215b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
322b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface =
323b7a08d04SJames Feist     "xyz.openbmc_project.Configuration.Stepwise";
32473df0db0SJames Feist static constexpr const char* thermalModeIface =
32573df0db0SJames Feist     "xyz.openbmc_project.Control.ThermalMode";
3269c310685SBorawski.Lukasz 
3278d1b46d7Szhanghch05 inline void
3288d1b46d7Szhanghch05     asyncPopulatePid(const std::string& connection, const std::string& path,
32973df0db0SJames Feist                      const std::string& currentProfile,
33073df0db0SJames Feist                      const std::vector<std::string>& supportedProfiles,
3318d1b46d7Szhanghch05                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3325b4aa86bSJames Feist {
3335eb468daSGeorge Liu     sdbusplus::message::object_path objPath(path);
3345eb468daSGeorge Liu     dbus::utility::getManagedObjects(
3355eb468daSGeorge Liu         connection, objPath,
33673df0db0SJames Feist         [asyncResp, currentProfile, supportedProfiles](
3375e7e2dc5SEd Tanous             const boost::system::error_code& ec,
3385b4aa86bSJames Feist             const dbus::utility::ManagedObjectType& managedObj) {
3395b4aa86bSJames Feist             if (ec)
3405b4aa86bSJames Feist             {
34162598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec);
342f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
3435b4aa86bSJames Feist                 return;
3445b4aa86bSJames Feist             }
3455b4aa86bSJames Feist             nlohmann::json& configRoot =
3465b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
3475b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
348bd79bce8SPatrick Williams             fans["@odata.type"] =
349bd79bce8SPatrick Williams                 "#OpenBMCManager.v1_0_0.Manager.FanControllers";
350253f11b8SEd Tanous             fans["@odata.id"] = boost::urls::format(
351253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
352253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
3535b4aa86bSJames Feist 
3545b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
355bd79bce8SPatrick Williams             pids["@odata.type"] =
356bd79bce8SPatrick Williams                 "#OpenBMCManager.v1_0_0.Manager.PidControllers";
357253f11b8SEd Tanous             pids["@odata.id"] = boost::urls::format(
358253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
359253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
3605b4aa86bSJames Feist 
361b7a08d04SJames Feist             nlohmann::json& stepwise = configRoot["StepwiseControllers"];
362fc1cdd14SEd Tanous             stepwise["@odata.type"] =
363fc1cdd14SEd Tanous                 "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
364253f11b8SEd Tanous             stepwise["@odata.id"] = boost::urls::format(
365253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
366253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
367b7a08d04SJames Feist 
3685b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
369253f11b8SEd Tanous             zones["@odata.id"] = boost::urls::format(
370253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
371253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
372fc1cdd14SEd Tanous             zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
373253f11b8SEd Tanous             configRoot["@odata.id"] =
374253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
375253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
376fc1cdd14SEd Tanous             configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
37773df0db0SJames Feist             configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
37873df0db0SJames Feist 
37973df0db0SJames Feist             if (!currentProfile.empty())
38073df0db0SJames Feist             {
38173df0db0SJames Feist                 configRoot["Profile"] = currentProfile;
38273df0db0SJames Feist             }
383bf2ddedeSCarson Labrado             BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
3845b4aa86bSJames Feist 
3855b4aa86bSJames Feist             for (const auto& pathPair : managedObj)
3865b4aa86bSJames Feist             {
3875b4aa86bSJames Feist                 for (const auto& intfPair : pathPair.second)
3885b4aa86bSJames Feist                 {
3895b4aa86bSJames Feist                     if (intfPair.first != pidConfigurationIface &&
390b7a08d04SJames Feist                         intfPair.first != pidZoneConfigurationIface &&
391b7a08d04SJames Feist                         intfPair.first != stepwiseConfigurationIface)
3925b4aa86bSJames Feist                     {
3935b4aa86bSJames Feist                         continue;
3945b4aa86bSJames Feist                     }
39573df0db0SJames Feist 
396711ac7a9SEd Tanous                     std::string name;
397711ac7a9SEd Tanous 
398711ac7a9SEd Tanous                     for (const std::pair<std::string,
399bd79bce8SPatrick Williams                                          dbus::utility::DbusVariantType>&
400bd79bce8SPatrick Williams                              propPair : intfPair.second)
401711ac7a9SEd Tanous                     {
402711ac7a9SEd Tanous                         if (propPair.first == "Name")
403711ac7a9SEd Tanous                         {
4045b4aa86bSJames Feist                             const std::string* namePtr =
405711ac7a9SEd Tanous                                 std::get_if<std::string>(&propPair.second);
4065b4aa86bSJames Feist                             if (namePtr == nullptr)
4075b4aa86bSJames Feist                             {
40862598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Pid Name Field illegal");
409b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
4105b4aa86bSJames Feist                                 return;
4115b4aa86bSJames Feist                             }
412db697703SWilly Tu                             name = *namePtr;
4135b4aa86bSJames Feist                             dbus::utility::escapePathForDbus(name);
414711ac7a9SEd Tanous                         }
415711ac7a9SEd Tanous                         else if (propPair.first == "Profiles")
41673df0db0SJames Feist                         {
41773df0db0SJames Feist                             const std::vector<std::string>* profiles =
41873df0db0SJames Feist                                 std::get_if<std::vector<std::string>>(
419711ac7a9SEd Tanous                                     &propPair.second);
42073df0db0SJames Feist                             if (profiles == nullptr)
42173df0db0SJames Feist                             {
42262598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
42373df0db0SJames Feist                                 messages::internalError(asyncResp->res);
42473df0db0SJames Feist                                 return;
42573df0db0SJames Feist                             }
42673df0db0SJames Feist                             if (std::find(profiles->begin(), profiles->end(),
42773df0db0SJames Feist                                           currentProfile) == profiles->end())
42873df0db0SJames Feist                             {
42962598e31SEd Tanous                                 BMCWEB_LOG_INFO(
430bd79bce8SPatrick Williams                                     "{} not supported in current profile",
431bd79bce8SPatrick Williams                                     name);
43273df0db0SJames Feist                                 continue;
43373df0db0SJames Feist                             }
43473df0db0SJames Feist                         }
435711ac7a9SEd Tanous                     }
436b7a08d04SJames Feist                     nlohmann::json* config = nullptr;
437c33a90ecSJames Feist                     const std::string* classPtr = nullptr;
438711ac7a9SEd Tanous 
439711ac7a9SEd Tanous                     for (const std::pair<std::string,
440bd79bce8SPatrick Williams                                          dbus::utility::DbusVariantType>&
441bd79bce8SPatrick Williams                              propPair : intfPair.second)
442c33a90ecSJames Feist                     {
443727dc83fSLei YU                         if (propPair.first == "Class")
444711ac7a9SEd Tanous                         {
445bd79bce8SPatrick Williams                             classPtr =
446bd79bce8SPatrick Williams                                 std::get_if<std::string>(&propPair.second);
447711ac7a9SEd Tanous                         }
448c33a90ecSJames Feist                     }
449c33a90ecSJames Feist 
450253f11b8SEd Tanous                     boost::urls::url url(
451253f11b8SEd Tanous                         boost::urls::format("/redfish/v1/Managers/{}",
452253f11b8SEd Tanous                                             BMCWEB_REDFISH_MANAGER_URI_NAME));
4535b4aa86bSJames Feist                     if (intfPair.first == pidZoneConfigurationIface)
4545b4aa86bSJames Feist                     {
4555b4aa86bSJames Feist                         std::string chassis;
456bd79bce8SPatrick Williams                         if (!dbus::utility::getNthStringFromPath(
457bd79bce8SPatrick Williams                                 pathPair.first.str, 5, chassis))
4585b4aa86bSJames Feist                         {
4595b4aa86bSJames Feist                             chassis = "#IllegalValue";
4605b4aa86bSJames Feist                         }
4615b4aa86bSJames Feist                         nlohmann::json& zone = zones[name];
462bd79bce8SPatrick Williams                         zone["Chassis"]["@odata.id"] = boost::urls::format(
463bd79bce8SPatrick Williams                             "/redfish/v1/Chassis/{}", chassis);
464eddfc437SWilly Tu                         url.set_fragment(
465eddfc437SWilly Tu                             ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
466eddfc437SWilly Tu                                 .to_string());
467eddfc437SWilly Tu                         zone["@odata.id"] = std::move(url);
468fc1cdd14SEd Tanous                         zone["@odata.type"] =
469fc1cdd14SEd Tanous                             "#OpenBMCManager.v1_0_0.Manager.FanZone";
470b7a08d04SJames Feist                         config = &zone;
4715b4aa86bSJames Feist                     }
4725b4aa86bSJames Feist 
473b7a08d04SJames Feist                     else if (intfPair.first == stepwiseConfigurationIface)
4745b4aa86bSJames Feist                     {
475c33a90ecSJames Feist                         if (classPtr == nullptr)
476c33a90ecSJames Feist                         {
47762598e31SEd Tanous                             BMCWEB_LOG_ERROR("Pid Class Field illegal");
478c33a90ecSJames Feist                             messages::internalError(asyncResp->res);
479c33a90ecSJames Feist                             return;
480c33a90ecSJames Feist                         }
481c33a90ecSJames Feist 
482b7a08d04SJames Feist                         nlohmann::json& controller = stepwise[name];
483b7a08d04SJames Feist                         config = &controller;
484eddfc437SWilly Tu                         url.set_fragment(
485eddfc437SWilly Tu                             ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
486eddfc437SWilly Tu                              name)
487eddfc437SWilly Tu                                 .to_string());
488eddfc437SWilly Tu                         controller["@odata.id"] = std::move(url);
489b7a08d04SJames Feist                         controller["@odata.type"] =
490fc1cdd14SEd Tanous                             "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
491b7a08d04SJames Feist 
492c33a90ecSJames Feist                         controller["Direction"] = *classPtr;
4935b4aa86bSJames Feist                     }
4945b4aa86bSJames Feist 
4955b4aa86bSJames Feist                     // pid and fans are off the same configuration
496b7a08d04SJames Feist                     else if (intfPair.first == pidConfigurationIface)
4975b4aa86bSJames Feist                     {
4985b4aa86bSJames Feist                         if (classPtr == nullptr)
4995b4aa86bSJames Feist                         {
50062598e31SEd Tanous                             BMCWEB_LOG_ERROR("Pid Class Field illegal");
501a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
5025b4aa86bSJames Feist                             return;
5035b4aa86bSJames Feist                         }
5045b4aa86bSJames Feist                         bool isFan = *classPtr == "fan";
505bd79bce8SPatrick Williams                         nlohmann::json& element =
506bd79bce8SPatrick Williams                             isFan ? fans[name] : pids[name];
507b7a08d04SJames Feist                         config = &element;
5085b4aa86bSJames Feist                         if (isFan)
5095b4aa86bSJames Feist                         {
510eddfc437SWilly Tu                             url.set_fragment(
511eddfc437SWilly Tu                                 ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
512eddfc437SWilly Tu                                  name)
513eddfc437SWilly Tu                                     .to_string());
514eddfc437SWilly Tu                             element["@odata.id"] = std::move(url);
515fc1cdd14SEd Tanous                             element["@odata.type"] =
516fc1cdd14SEd Tanous                                 "#OpenBMCManager.v1_0_0.Manager.FanController";
5175b4aa86bSJames Feist                         }
5185b4aa86bSJames Feist                         else
5195b4aa86bSJames Feist                         {
520eddfc437SWilly Tu                             url.set_fragment(
521eddfc437SWilly Tu                                 ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
522eddfc437SWilly Tu                                  name)
523eddfc437SWilly Tu                                     .to_string());
524eddfc437SWilly Tu                             element["@odata.id"] = std::move(url);
525fc1cdd14SEd Tanous                             element["@odata.type"] =
526fc1cdd14SEd Tanous                                 "#OpenBMCManager.v1_0_0.Manager.PidController";
5275b4aa86bSJames Feist                         }
528b7a08d04SJames Feist                     }
529b7a08d04SJames Feist                     else
530b7a08d04SJames Feist                     {
53162598e31SEd Tanous                         BMCWEB_LOG_ERROR("Unexpected configuration");
532b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
533b7a08d04SJames Feist                         return;
534b7a08d04SJames Feist                     }
535b7a08d04SJames Feist 
536b7a08d04SJames Feist                     // used for making maps out of 2 vectors
537b7a08d04SJames Feist                     const std::vector<double>* keys = nullptr;
538b7a08d04SJames Feist                     const std::vector<double>* values = nullptr;
539b7a08d04SJames Feist 
540b7a08d04SJames Feist                     for (const auto& propertyPair : intfPair.second)
541b7a08d04SJames Feist                     {
542b7a08d04SJames Feist                         if (propertyPair.first == "Type" ||
543b7a08d04SJames Feist                             propertyPair.first == "Class" ||
544b7a08d04SJames Feist                             propertyPair.first == "Name")
545b7a08d04SJames Feist                         {
546b7a08d04SJames Feist                             continue;
547b7a08d04SJames Feist                         }
548b7a08d04SJames Feist 
549b7a08d04SJames Feist                         // zones
550b7a08d04SJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
551b7a08d04SJames Feist                         {
552b7a08d04SJames Feist                             const double* ptr =
553abf2add6SEd Tanous                                 std::get_if<double>(&propertyPair.second);
554b7a08d04SJames Feist                             if (ptr == nullptr)
555b7a08d04SJames Feist                             {
55662598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Field Illegal {}",
55762598e31SEd Tanous                                                  propertyPair.first);
558b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
559b7a08d04SJames Feist                                 return;
560b7a08d04SJames Feist                             }
561b7a08d04SJames Feist                             (*config)[propertyPair.first] = *ptr;
562b7a08d04SJames Feist                         }
563b7a08d04SJames Feist 
564b7a08d04SJames Feist                         if (intfPair.first == stepwiseConfigurationIface)
565b7a08d04SJames Feist                         {
566b7a08d04SJames Feist                             if (propertyPair.first == "Reading" ||
567b7a08d04SJames Feist                                 propertyPair.first == "Output")
568b7a08d04SJames Feist                             {
569b7a08d04SJames Feist                                 const std::vector<double>* ptr =
570abf2add6SEd Tanous                                     std::get_if<std::vector<double>>(
571b7a08d04SJames Feist                                         &propertyPair.second);
572b7a08d04SJames Feist 
573b7a08d04SJames Feist                                 if (ptr == nullptr)
574b7a08d04SJames Feist                                 {
57562598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
57662598e31SEd Tanous                                                      propertyPair.first);
577b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
578b7a08d04SJames Feist                                     return;
579b7a08d04SJames Feist                                 }
580b7a08d04SJames Feist 
581b7a08d04SJames Feist                                 if (propertyPair.first == "Reading")
582b7a08d04SJames Feist                                 {
583b7a08d04SJames Feist                                     keys = ptr;
584b7a08d04SJames Feist                                 }
585b7a08d04SJames Feist                                 else
586b7a08d04SJames Feist                                 {
587b7a08d04SJames Feist                                     values = ptr;
588b7a08d04SJames Feist                                 }
589e662eae8SEd Tanous                                 if (keys != nullptr && values != nullptr)
590b7a08d04SJames Feist                                 {
591b7a08d04SJames Feist                                     if (keys->size() != values->size())
592b7a08d04SJames Feist                                     {
59362598e31SEd Tanous                                         BMCWEB_LOG_ERROR(
59462598e31SEd Tanous                                             "Reading and Output size don't match ");
595b7a08d04SJames Feist                                         messages::internalError(asyncResp->res);
596b7a08d04SJames Feist                                         return;
597b7a08d04SJames Feist                                     }
598b7a08d04SJames Feist                                     nlohmann::json& steps = (*config)["Steps"];
599b7a08d04SJames Feist                                     steps = nlohmann::json::array();
600b7a08d04SJames Feist                                     for (size_t ii = 0; ii < keys->size(); ii++)
601b7a08d04SJames Feist                                     {
6021476687dSEd Tanous                                         nlohmann::json::object_t step;
6031476687dSEd Tanous                                         step["Target"] = (*keys)[ii];
6041476687dSEd Tanous                                         step["Output"] = (*values)[ii];
605b2ba3072SPatrick Williams                                         steps.emplace_back(std::move(step));
606b7a08d04SJames Feist                                     }
607b7a08d04SJames Feist                                 }
608b7a08d04SJames Feist                             }
609b7a08d04SJames Feist                             if (propertyPair.first == "NegativeHysteresis" ||
610b7a08d04SJames Feist                                 propertyPair.first == "PositiveHysteresis")
611b7a08d04SJames Feist                             {
612b7a08d04SJames Feist                                 const double* ptr =
613abf2add6SEd Tanous                                     std::get_if<double>(&propertyPair.second);
614b7a08d04SJames Feist                                 if (ptr == nullptr)
615b7a08d04SJames Feist                                 {
61662598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
61762598e31SEd Tanous                                                      propertyPair.first);
618b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
619b7a08d04SJames Feist                                     return;
620b7a08d04SJames Feist                                 }
621b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
622b7a08d04SJames Feist                             }
623b7a08d04SJames Feist                         }
624b7a08d04SJames Feist 
625b7a08d04SJames Feist                         // pid and fans are off the same configuration
626b7a08d04SJames Feist                         if (intfPair.first == pidConfigurationIface ||
627b7a08d04SJames Feist                             intfPair.first == stepwiseConfigurationIface)
628b7a08d04SJames Feist                         {
6295b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
6305b4aa86bSJames Feist                             {
6315b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
632abf2add6SEd Tanous                                     std::get_if<std::vector<std::string>>(
6331b6b96c5SEd Tanous                                         &propertyPair.second);
6345b4aa86bSJames Feist 
6355b4aa86bSJames Feist                                 if (inputs == nullptr)
6365b4aa86bSJames Feist                                 {
63762598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
638a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
6395b4aa86bSJames Feist                                     return;
6405b4aa86bSJames Feist                                 }
641b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
6425b4aa86bSJames Feist                                 data = nlohmann::json::array();
6435b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
6445b4aa86bSJames Feist                                 {
6455b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
6461476687dSEd Tanous                                     nlohmann::json::object_t input;
647bd79bce8SPatrick Williams                                     boost::urls::url managerUrl =
648bd79bce8SPatrick Williams                                         boost::urls::format(
649253f11b8SEd Tanous                                             "/redfish/v1/Managers/{}#{}",
650253f11b8SEd Tanous                                             BMCWEB_REDFISH_MANAGER_URI_NAME,
651eddfc437SWilly Tu                                             ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
652eddfc437SWilly Tu                                              itemCopy)
653eddfc437SWilly Tu                                                 .to_string());
654eddfc437SWilly Tu                                     input["@odata.id"] = std::move(managerUrl);
655b2ba3072SPatrick Williams                                     data.emplace_back(std::move(input));
6565b4aa86bSJames Feist                                 }
6575b4aa86bSJames Feist                             }
6585b4aa86bSJames Feist                             // todo(james): may never happen, but this
6595b4aa86bSJames Feist                             // assumes configuration data referenced in the
6605b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
6615b4aa86bSJames Feist                             // could add another loop to cover all cases,
6625b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
6635b4aa86bSJames Feist                             // bit
6645b4aa86bSJames Feist 
6655b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
6665b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
6675b4aa86bSJames Feist                             {
668b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
6695b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
670abf2add6SEd Tanous                                     std::get_if<std::vector<std::string>>(
6711b6b96c5SEd Tanous                                         &propertyPair.second);
6725b4aa86bSJames Feist 
6735b4aa86bSJames Feist                                 if (inputs == nullptr)
6745b4aa86bSJames Feist                                 {
67562598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
67662598e31SEd Tanous                                                      propertyPair.first);
677f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
6785b4aa86bSJames Feist                                     return;
6795b4aa86bSJames Feist                                 }
6805b4aa86bSJames Feist                                 data = *inputs;
681b943aaefSJames Feist                             }
682b943aaefSJames Feist                             else if (propertyPair.first == "SetPointOffset")
683b943aaefSJames Feist                             {
684b943aaefSJames Feist                                 const std::string* ptr =
685bd79bce8SPatrick Williams                                     std::get_if<std::string>(
686bd79bce8SPatrick Williams                                         &propertyPair.second);
687b943aaefSJames Feist 
688b943aaefSJames Feist                                 if (ptr == nullptr)
689b943aaefSJames Feist                                 {
69062598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
69162598e31SEd Tanous                                                      propertyPair.first);
692b943aaefSJames Feist                                     messages::internalError(asyncResp->res);
693b943aaefSJames Feist                                     return;
694b943aaefSJames Feist                                 }
695b943aaefSJames Feist                                 // translate from dbus to redfish
696b943aaefSJames Feist                                 if (*ptr == "WarningHigh")
697b943aaefSJames Feist                                 {
698b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
699b943aaefSJames Feist                                         "UpperThresholdNonCritical";
700b943aaefSJames Feist                                 }
701b943aaefSJames Feist                                 else if (*ptr == "WarningLow")
702b943aaefSJames Feist                                 {
703b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
704b943aaefSJames Feist                                         "LowerThresholdNonCritical";
705b943aaefSJames Feist                                 }
706b943aaefSJames Feist                                 else if (*ptr == "CriticalHigh")
707b943aaefSJames Feist                                 {
708b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
709b943aaefSJames Feist                                         "UpperThresholdCritical";
710b943aaefSJames Feist                                 }
711b943aaefSJames Feist                                 else if (*ptr == "CriticalLow")
712b943aaefSJames Feist                                 {
713b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
714b943aaefSJames Feist                                         "LowerThresholdCritical";
715b943aaefSJames Feist                                 }
716b943aaefSJames Feist                                 else
717b943aaefSJames Feist                                 {
71862598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
719b943aaefSJames Feist                                     messages::internalError(asyncResp->res);
720b943aaefSJames Feist                                     return;
721b943aaefSJames Feist                                 }
722b943aaefSJames Feist                             }
723b943aaefSJames Feist                             // doubles
724bd79bce8SPatrick Williams                             else if (propertyPair.first ==
725bd79bce8SPatrick Williams                                          "FFGainCoefficient" ||
7265b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
7275b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
7285b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
7295b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
730bd79bce8SPatrick Williams                                      propertyPair.first ==
731bd79bce8SPatrick Williams                                          "PositiveHysteresis" ||
732bd79bce8SPatrick Williams                                      propertyPair.first ==
733bd79bce8SPatrick Williams                                          "NegativeHysteresis" ||
7345b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
7355b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
7365b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
7377625cb81SJames Feist                                      propertyPair.first == "SetPoint" ||
7385b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
7395b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
7405b4aa86bSJames Feist                             {
7415b4aa86bSJames Feist                                 const double* ptr =
742abf2add6SEd Tanous                                     std::get_if<double>(&propertyPair.second);
7435b4aa86bSJames Feist                                 if (ptr == nullptr)
7445b4aa86bSJames Feist                                 {
74562598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
74662598e31SEd Tanous                                                      propertyPair.first);
747f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
7485b4aa86bSJames Feist                                     return;
7495b4aa86bSJames Feist                                 }
750b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
7515b4aa86bSJames Feist                             }
7525b4aa86bSJames Feist                         }
7535b4aa86bSJames Feist                     }
7545b4aa86bSJames Feist                 }
7555b4aa86bSJames Feist             }
7565eb468daSGeorge Liu         });
7575b4aa86bSJames Feist }
758ca537928SJennifer Lee 
75983ff9ab6SJames Feist enum class CreatePIDRet
76083ff9ab6SJames Feist {
76183ff9ab6SJames Feist     fail,
76283ff9ab6SJames Feist     del,
76383ff9ab6SJames Feist     patch
76483ff9ab6SJames Feist };
76583ff9ab6SJames Feist 
7668d1b46d7Szhanghch05 inline bool
7678d1b46d7Szhanghch05     getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response,
7689e9b6049SEd Tanous                         std::vector<nlohmann::json::object_t>& config,
7695f2caaefSJames Feist                         std::vector<std::string>& zones)
7705f2caaefSJames Feist {
771b6baeaa4SJames Feist     if (config.empty())
772b6baeaa4SJames Feist     {
77362598e31SEd Tanous         BMCWEB_LOG_ERROR("Empty Zones");
774f818b04dSEd Tanous         messages::propertyValueFormatError(response->res, config, "Zones");
775b6baeaa4SJames Feist         return false;
776b6baeaa4SJames Feist     }
7775f2caaefSJames Feist     for (auto& odata : config)
7785f2caaefSJames Feist     {
7795f2caaefSJames Feist         std::string path;
7809e9b6049SEd Tanous         if (!redfish::json_util::readJsonObject(odata, response->res,
7819e9b6049SEd Tanous                                                 "@odata.id", path))
7825f2caaefSJames Feist         {
7835f2caaefSJames Feist             return false;
7845f2caaefSJames Feist         }
7855f2caaefSJames Feist         std::string input;
78661adbda3SJames Feist 
78761adbda3SJames Feist         // 8 below comes from
78861adbda3SJames Feist         // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
78961adbda3SJames Feist         //     0    1     2      3    4    5      6     7      8
79061adbda3SJames Feist         if (!dbus::utility::getNthStringFromPath(path, 8, input))
7915f2caaefSJames Feist         {
79262598e31SEd Tanous             BMCWEB_LOG_ERROR("Got invalid path {}", path);
79362598e31SEd Tanous             BMCWEB_LOG_ERROR("Illegal Type Zones");
794f818b04dSEd Tanous             messages::propertyValueFormatError(response->res, odata, "Zones");
7955f2caaefSJames Feist             return false;
7965f2caaefSJames Feist         }
797a170f275SEd Tanous         std::replace(input.begin(), input.end(), '_', ' ');
7985f2caaefSJames Feist         zones.emplace_back(std::move(input));
7995f2caaefSJames Feist     }
8005f2caaefSJames Feist     return true;
8015f2caaefSJames Feist }
8025f2caaefSJames Feist 
803711ac7a9SEd Tanous inline const dbus::utility::ManagedObjectType::value_type*
80473df0db0SJames Feist     findChassis(const dbus::utility::ManagedObjectType& managedObj,
8059e9b6049SEd Tanous                 std::string_view value, std::string& chassis)
806b6baeaa4SJames Feist {
80762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
808b6baeaa4SJames Feist 
8099e9b6049SEd Tanous     std::string escaped(value);
8106ce82fabSYaswanth Reddy M     std::replace(escaped.begin(), escaped.end(), ' ', '_');
811b6baeaa4SJames Feist     escaped = "/" + escaped;
8123544d2a7SEd Tanous     auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
81318f8f608SEd Tanous         if (obj.first.str.ends_with(escaped))
814b6baeaa4SJames Feist         {
81562598e31SEd Tanous             BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
816b6baeaa4SJames Feist             return true;
817b6baeaa4SJames Feist         }
818b6baeaa4SJames Feist         return false;
819b6baeaa4SJames Feist     });
820b6baeaa4SJames Feist 
821b6baeaa4SJames Feist     if (it == managedObj.end())
822b6baeaa4SJames Feist     {
82373df0db0SJames Feist         return nullptr;
824b6baeaa4SJames Feist     }
825b6baeaa4SJames Feist     // 5 comes from <chassis-name> being the 5th element
826b6baeaa4SJames Feist     // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
82773df0db0SJames Feist     if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
82873df0db0SJames Feist     {
82973df0db0SJames Feist         return &(*it);
83073df0db0SJames Feist     }
83173df0db0SJames Feist 
83273df0db0SJames Feist     return nullptr;
833b6baeaa4SJames Feist }
834b6baeaa4SJames Feist 
83523a21a1cSEd Tanous inline CreatePIDRet createPidInterface(
8368d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
8379e9b6049SEd Tanous     std::string_view name, nlohmann::json& jsonValue, const std::string& path,
83883ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
839b9d36b47SEd Tanous     dbus::utility::DBusPropertiesMap& output, std::string& chassis,
840b9d36b47SEd Tanous     const std::string& profile)
84183ff9ab6SJames Feist {
8425f2caaefSJames Feist     // common deleter
8439e9b6049SEd Tanous     if (jsonValue == nullptr)
8445f2caaefSJames Feist     {
8455f2caaefSJames Feist         std::string iface;
8465f2caaefSJames Feist         if (type == "PidControllers" || type == "FanControllers")
8475f2caaefSJames Feist         {
8485f2caaefSJames Feist             iface = pidConfigurationIface;
8495f2caaefSJames Feist         }
8505f2caaefSJames Feist         else if (type == "FanZones")
8515f2caaefSJames Feist         {
8525f2caaefSJames Feist             iface = pidZoneConfigurationIface;
8535f2caaefSJames Feist         }
8545f2caaefSJames Feist         else if (type == "StepwiseControllers")
8555f2caaefSJames Feist         {
8565f2caaefSJames Feist             iface = stepwiseConfigurationIface;
8575f2caaefSJames Feist         }
8585f2caaefSJames Feist         else
8595f2caaefSJames Feist         {
86062598e31SEd Tanous             BMCWEB_LOG_ERROR("Illegal Type {}", type);
8615f2caaefSJames Feist             messages::propertyUnknown(response->res, type);
8625f2caaefSJames Feist             return CreatePIDRet::fail;
8635f2caaefSJames Feist         }
8646ee7f774SJames Feist 
86562598e31SEd Tanous         BMCWEB_LOG_DEBUG("del {} {}", path, iface);
8665f2caaefSJames Feist         // delete interface
8675f2caaefSJames Feist         crow::connections::systemBus->async_method_call(
8685e7e2dc5SEd Tanous             [response, path](const boost::system::error_code& ec) {
8695f2caaefSJames Feist                 if (ec)
8705f2caaefSJames Feist                 {
87162598e31SEd Tanous                     BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
8725f2caaefSJames Feist                     messages::internalError(response->res);
873b6baeaa4SJames Feist                     return;
8745f2caaefSJames Feist                 }
875b6baeaa4SJames Feist                 messages::success(response->res);
8765f2caaefSJames Feist             },
8775f2caaefSJames Feist             "xyz.openbmc_project.EntityManager", path, iface, "Delete");
8785f2caaefSJames Feist         return CreatePIDRet::del;
8795f2caaefSJames Feist     }
8805f2caaefSJames Feist 
881711ac7a9SEd Tanous     const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
882b6baeaa4SJames Feist     if (!createNewObject)
883b6baeaa4SJames Feist     {
884b6baeaa4SJames Feist         // if we aren't creating a new object, we should be able to find it on
885b6baeaa4SJames Feist         // d-bus
8869e9b6049SEd Tanous         managedItem = findChassis(managedObj, name, chassis);
88773df0db0SJames Feist         if (managedItem == nullptr)
888b6baeaa4SJames Feist         {
88962598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
890ef4c65b7SEd Tanous             messages::invalidObject(
891ef4c65b7SEd Tanous                 response->res,
892ef4c65b7SEd Tanous                 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
893b6baeaa4SJames Feist             return CreatePIDRet::fail;
894b6baeaa4SJames Feist         }
895b6baeaa4SJames Feist     }
896b6baeaa4SJames Feist 
89726f6976fSEd Tanous     if (!profile.empty() &&
89873df0db0SJames Feist         (type == "PidControllers" || type == "FanControllers" ||
89973df0db0SJames Feist          type == "StepwiseControllers"))
90073df0db0SJames Feist     {
90173df0db0SJames Feist         if (managedItem == nullptr)
90273df0db0SJames Feist         {
903b9d36b47SEd Tanous             output.emplace_back("Profiles", std::vector<std::string>{profile});
90473df0db0SJames Feist         }
90573df0db0SJames Feist         else
90673df0db0SJames Feist         {
90773df0db0SJames Feist             std::string interface;
90873df0db0SJames Feist             if (type == "StepwiseControllers")
90973df0db0SJames Feist             {
91073df0db0SJames Feist                 interface = stepwiseConfigurationIface;
91173df0db0SJames Feist             }
91273df0db0SJames Feist             else
91373df0db0SJames Feist             {
91473df0db0SJames Feist                 interface = pidConfigurationIface;
91573df0db0SJames Feist             }
916711ac7a9SEd Tanous             bool ifaceFound = false;
917711ac7a9SEd Tanous             for (const auto& iface : managedItem->second)
918711ac7a9SEd Tanous             {
919711ac7a9SEd Tanous                 if (iface.first == interface)
920711ac7a9SEd Tanous                 {
921711ac7a9SEd Tanous                     ifaceFound = true;
922711ac7a9SEd Tanous                     for (const auto& prop : iface.second)
923711ac7a9SEd Tanous                     {
924711ac7a9SEd Tanous                         if (prop.first == "Profiles")
925711ac7a9SEd Tanous                         {
926711ac7a9SEd Tanous                             const std::vector<std::string>* curProfiles =
927711ac7a9SEd Tanous                                 std::get_if<std::vector<std::string>>(
928711ac7a9SEd Tanous                                     &(prop.second));
929711ac7a9SEd Tanous                             if (curProfiles == nullptr)
930711ac7a9SEd Tanous                             {
93162598e31SEd Tanous                                 BMCWEB_LOG_ERROR(
93262598e31SEd Tanous                                     "Illegal profiles in managed object");
933711ac7a9SEd Tanous                                 messages::internalError(response->res);
934711ac7a9SEd Tanous                                 return CreatePIDRet::fail;
935711ac7a9SEd Tanous                             }
936711ac7a9SEd Tanous                             if (std::find(curProfiles->begin(),
937bd79bce8SPatrick Williams                                           curProfiles->end(), profile) ==
938bd79bce8SPatrick Williams                                 curProfiles->end())
939711ac7a9SEd Tanous                             {
940711ac7a9SEd Tanous                                 std::vector<std::string> newProfiles =
941711ac7a9SEd Tanous                                     *curProfiles;
942711ac7a9SEd Tanous                                 newProfiles.push_back(profile);
943b9d36b47SEd Tanous                                 output.emplace_back("Profiles", newProfiles);
944711ac7a9SEd Tanous                             }
945711ac7a9SEd Tanous                         }
946711ac7a9SEd Tanous                     }
947711ac7a9SEd Tanous                 }
948711ac7a9SEd Tanous             }
949711ac7a9SEd Tanous 
950711ac7a9SEd Tanous             if (!ifaceFound)
95173df0db0SJames Feist             {
95262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to find interface in managed object");
95373df0db0SJames Feist                 messages::internalError(response->res);
95473df0db0SJames Feist                 return CreatePIDRet::fail;
95573df0db0SJames Feist             }
95673df0db0SJames Feist         }
95773df0db0SJames Feist     }
95873df0db0SJames Feist 
95983ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
96083ff9ab6SJames Feist     {
96183ff9ab6SJames Feist         if (createNewObject)
96283ff9ab6SJames Feist         {
963b9d36b47SEd Tanous             output.emplace_back("Class",
964b9d36b47SEd Tanous                                 type == "PidControllers" ? "temp" : "fan");
965b9d36b47SEd Tanous             output.emplace_back("Type", "Pid");
96683ff9ab6SJames Feist         }
9675f2caaefSJames Feist 
9689e9b6049SEd Tanous         std::optional<std::vector<nlohmann::json::object_t>> zones;
9695f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
9705f2caaefSJames Feist         std::optional<std::vector<std::string>> outputs;
9715f2caaefSJames Feist         std::map<std::string, std::optional<double>> doubles;
972b943aaefSJames Feist         std::optional<std::string> setpointOffset;
973*afc474aeSMyung Bae         if (!redfish::json_util::readJson( //
974*afc474aeSMyung Bae                 jsonValue, response->res, //
975*afc474aeSMyung Bae                 "FFGainCoefficient", doubles["FFGainCoefficient"], //
976*afc474aeSMyung Bae                 "FFOffCoefficient", doubles["FFOffCoefficient"], //
977*afc474aeSMyung Bae                 "ICoefficient", doubles["ICoefficient"], //
978*afc474aeSMyung Bae                 "ILimitMax", doubles["ILimitMax"], //
979*afc474aeSMyung Bae                 "ILimitMin", doubles["ILimitMin"], //
980*afc474aeSMyung Bae                 "Inputs", inputs, //
981*afc474aeSMyung Bae                 "NegativeHysteresis", doubles["NegativeHysteresis"], //
982*afc474aeSMyung Bae                 "OutLimitMax", doubles["OutLimitMax"], //
983*afc474aeSMyung Bae                 "OutLimitMin", doubles["OutLimitMin"], //
984*afc474aeSMyung Bae                 "Outputs", outputs, //
985*afc474aeSMyung Bae                 "PCoefficient", doubles["PCoefficient"], //
986*afc474aeSMyung Bae                 "PositiveHysteresis", doubles["PositiveHysteresis"], //
987*afc474aeSMyung Bae                 "SetPoint", doubles["SetPoint"], //
988*afc474aeSMyung Bae                 "SetPointOffset", setpointOffset, //
989*afc474aeSMyung Bae                 "SlewNeg", doubles["SlewNeg"], //
990*afc474aeSMyung Bae                 "SlewPos", doubles["SlewPos"], //
991*afc474aeSMyung Bae                 "Zones", zones //
992*afc474aeSMyung Bae                 ))
99383ff9ab6SJames Feist         {
9945f2caaefSJames Feist             return CreatePIDRet::fail;
99583ff9ab6SJames Feist         }
996*afc474aeSMyung Bae 
9975f2caaefSJames Feist         if (zones)
9985f2caaefSJames Feist         {
9995f2caaefSJames Feist             std::vector<std::string> zonesStr;
10005f2caaefSJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStr))
10015f2caaefSJames Feist             {
100262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Illegal Zones");
10035f2caaefSJames Feist                 return CreatePIDRet::fail;
10045f2caaefSJames Feist             }
1005b6baeaa4SJames Feist             if (chassis.empty() &&
1006e662eae8SEd Tanous                 findChassis(managedObj, zonesStr[0], chassis) == nullptr)
1007b6baeaa4SJames Feist             {
100862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
1009ace85d60SEd Tanous                 messages::invalidObject(
1010ef4c65b7SEd Tanous                     response->res,
1011ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", chassis));
1012b6baeaa4SJames Feist                 return CreatePIDRet::fail;
1013b6baeaa4SJames Feist             }
1014b9d36b47SEd Tanous             output.emplace_back("Zones", std::move(zonesStr));
10155f2caaefSJames Feist         }
1016afb9ee06SEd Tanous 
1017afb9ee06SEd Tanous         if (inputs)
10185f2caaefSJames Feist         {
1019afb9ee06SEd Tanous             for (std::string& value : *inputs)
102083ff9ab6SJames Feist             {
1021a170f275SEd Tanous                 std::replace(value.begin(), value.end(), '_', ' ');
102283ff9ab6SJames Feist             }
1023afb9ee06SEd Tanous             output.emplace_back("Inputs", *inputs);
1024afb9ee06SEd Tanous         }
1025afb9ee06SEd Tanous 
1026afb9ee06SEd Tanous         if (outputs)
10275f2caaefSJames Feist         {
1028afb9ee06SEd Tanous             for (std::string& value : *outputs)
10295f2caaefSJames Feist             {
1030afb9ee06SEd Tanous                 std::replace(value.begin(), value.end(), '_', ' ');
10315f2caaefSJames Feist             }
1032afb9ee06SEd Tanous             output.emplace_back("Outputs", *outputs);
103383ff9ab6SJames Feist         }
103483ff9ab6SJames Feist 
1035b943aaefSJames Feist         if (setpointOffset)
1036b943aaefSJames Feist         {
1037b943aaefSJames Feist             // translate between redfish and dbus names
1038b943aaefSJames Feist             if (*setpointOffset == "UpperThresholdNonCritical")
1039b943aaefSJames Feist             {
1040b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "WarningLow");
1041b943aaefSJames Feist             }
1042b943aaefSJames Feist             else if (*setpointOffset == "LowerThresholdNonCritical")
1043b943aaefSJames Feist             {
1044b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "WarningHigh");
1045b943aaefSJames Feist             }
1046b943aaefSJames Feist             else if (*setpointOffset == "LowerThresholdCritical")
1047b943aaefSJames Feist             {
1048b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "CriticalLow");
1049b943aaefSJames Feist             }
1050b943aaefSJames Feist             else if (*setpointOffset == "UpperThresholdCritical")
1051b943aaefSJames Feist             {
1052b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "CriticalHigh");
1053b943aaefSJames Feist             }
1054b943aaefSJames Feist             else
1055b943aaefSJames Feist             {
105662598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
10579e9b6049SEd Tanous                 messages::propertyValueNotInList(response->res, name,
1058ace85d60SEd Tanous                                                  "SetPointOffset");
1059b943aaefSJames Feist                 return CreatePIDRet::fail;
1060b943aaefSJames Feist             }
1061b943aaefSJames Feist         }
1062b943aaefSJames Feist 
106383ff9ab6SJames Feist         // doubles
10645f2caaefSJames Feist         for (const auto& pairs : doubles)
106583ff9ab6SJames Feist         {
10665f2caaefSJames Feist             if (!pairs.second)
106783ff9ab6SJames Feist             {
10685f2caaefSJames Feist                 continue;
106983ff9ab6SJames Feist             }
107062598e31SEd Tanous             BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
1071b9d36b47SEd Tanous             output.emplace_back(pairs.first, *pairs.second);
10725f2caaefSJames Feist         }
107383ff9ab6SJames Feist     }
107483ff9ab6SJames Feist 
107583ff9ab6SJames Feist     else if (type == "FanZones")
107683ff9ab6SJames Feist     {
1077b9d36b47SEd Tanous         output.emplace_back("Type", "Pid.Zone");
107883ff9ab6SJames Feist 
10799e9b6049SEd Tanous         std::optional<std::string> chassisId;
10805f2caaefSJames Feist         std::optional<double> failSafePercent;
1081d3ec07f8SJames Feist         std::optional<double> minThermalOutput;
1082*afc474aeSMyung Bae         if (!redfish::json_util::readJson( //
1083*afc474aeSMyung Bae                 jsonValue, response->res, //
1084*afc474aeSMyung Bae                 "Chassis/@odata.id", chassisId, //
1085*afc474aeSMyung Bae                 "FailSafePercent", failSafePercent, //
1086*afc474aeSMyung Bae                 "MinThermalOutput", minThermalOutput))
108783ff9ab6SJames Feist         {
108883ff9ab6SJames Feist             return CreatePIDRet::fail;
108983ff9ab6SJames Feist         }
10905f2caaefSJames Feist 
10919e9b6049SEd Tanous         if (chassisId)
109283ff9ab6SJames Feist         {
1093717794d5SAppaRao Puli             // /redfish/v1/chassis/chassis_name/
10949e9b6049SEd Tanous             if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
109583ff9ab6SJames Feist             {
10969e9b6049SEd Tanous                 BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
1097ace85d60SEd Tanous                 messages::invalidObject(
1098ef4c65b7SEd Tanous                     response->res,
10999e9b6049SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
110083ff9ab6SJames Feist                 return CreatePIDRet::fail;
110183ff9ab6SJames Feist             }
110283ff9ab6SJames Feist         }
1103d3ec07f8SJames Feist         if (minThermalOutput)
110483ff9ab6SJames Feist         {
1105b9d36b47SEd Tanous             output.emplace_back("MinThermalOutput", *minThermalOutput);
11065f2caaefSJames Feist         }
11075f2caaefSJames Feist         if (failSafePercent)
110883ff9ab6SJames Feist         {
1109b9d36b47SEd Tanous             output.emplace_back("FailSafePercent", *failSafePercent);
11105f2caaefSJames Feist         }
11115f2caaefSJames Feist     }
11125f2caaefSJames Feist     else if (type == "StepwiseControllers")
11135f2caaefSJames Feist     {
1114b9d36b47SEd Tanous         output.emplace_back("Type", "Stepwise");
11155f2caaefSJames Feist 
11169e9b6049SEd Tanous         std::optional<std::vector<nlohmann::json::object_t>> zones;
11179e9b6049SEd Tanous         std::optional<std::vector<nlohmann::json::object_t>> steps;
11185f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
11195f2caaefSJames Feist         std::optional<double> positiveHysteresis;
11205f2caaefSJames Feist         std::optional<double> negativeHysteresis;
1121c33a90ecSJames Feist         std::optional<std::string> direction; // upper clipping curve vs lower
1122*afc474aeSMyung Bae         if (!redfish::json_util::readJson( //
1123*afc474aeSMyung Bae                 jsonValue, response->res, //
1124*afc474aeSMyung Bae                 "Direction", direction, //
1125*afc474aeSMyung Bae                 "Inputs", inputs, //
1126*afc474aeSMyung Bae                 "NegativeHysteresis", negativeHysteresis, //
1127*afc474aeSMyung Bae                 "PositiveHysteresis", positiveHysteresis, //
1128*afc474aeSMyung Bae                 "Steps", steps, //
1129*afc474aeSMyung Bae                 "Zones", zones //
1130*afc474aeSMyung Bae                 ))
11315f2caaefSJames Feist         {
113283ff9ab6SJames Feist             return CreatePIDRet::fail;
113383ff9ab6SJames Feist         }
11345f2caaefSJames Feist 
11355f2caaefSJames Feist         if (zones)
113683ff9ab6SJames Feist         {
1137b6baeaa4SJames Feist             std::vector<std::string> zonesStrs;
1138b6baeaa4SJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStrs))
11395f2caaefSJames Feist             {
114062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Illegal Zones");
114183ff9ab6SJames Feist                 return CreatePIDRet::fail;
114283ff9ab6SJames Feist             }
1143b6baeaa4SJames Feist             if (chassis.empty() &&
1144e662eae8SEd Tanous                 findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
1145b6baeaa4SJames Feist             {
114662598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
1147ace85d60SEd Tanous                 messages::invalidObject(
1148ef4c65b7SEd Tanous                     response->res,
1149ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", chassis));
1150b6baeaa4SJames Feist                 return CreatePIDRet::fail;
1151b6baeaa4SJames Feist             }
1152b9d36b47SEd Tanous             output.emplace_back("Zones", std::move(zonesStrs));
11535f2caaefSJames Feist         }
11545f2caaefSJames Feist         if (steps)
11555f2caaefSJames Feist         {
11565f2caaefSJames Feist             std::vector<double> readings;
11575f2caaefSJames Feist             std::vector<double> outputs;
11585f2caaefSJames Feist             for (auto& step : *steps)
11595f2caaefSJames Feist             {
1160543f4400SEd Tanous                 double target = 0.0;
1161543f4400SEd Tanous                 double out = 0.0;
11625f2caaefSJames Feist 
1163*afc474aeSMyung Bae                 if (!redfish::json_util::readJsonObject( //
1164*afc474aeSMyung Bae                         step, response->res, //
1165*afc474aeSMyung Bae                         "Output", out, //
1166*afc474aeSMyung Bae                         "Target", target //
1167*afc474aeSMyung Bae                         ))
11685f2caaefSJames Feist                 {
11695f2caaefSJames Feist                     return CreatePIDRet::fail;
11705f2caaefSJames Feist                 }
11715f2caaefSJames Feist                 readings.emplace_back(target);
117223a21a1cSEd Tanous                 outputs.emplace_back(out);
11735f2caaefSJames Feist             }
1174b9d36b47SEd Tanous             output.emplace_back("Reading", std::move(readings));
1175b9d36b47SEd Tanous             output.emplace_back("Output", std::move(outputs));
11765f2caaefSJames Feist         }
11775f2caaefSJames Feist         if (inputs)
11785f2caaefSJames Feist         {
11795f2caaefSJames Feist             for (std::string& value : *inputs)
11805f2caaefSJames Feist             {
1181a170f275SEd Tanous                 std::replace(value.begin(), value.end(), '_', ' ');
11825f2caaefSJames Feist             }
1183b9d36b47SEd Tanous             output.emplace_back("Inputs", std::move(*inputs));
11845f2caaefSJames Feist         }
11855f2caaefSJames Feist         if (negativeHysteresis)
11865f2caaefSJames Feist         {
1187b9d36b47SEd Tanous             output.emplace_back("NegativeHysteresis", *negativeHysteresis);
11885f2caaefSJames Feist         }
11895f2caaefSJames Feist         if (positiveHysteresis)
11905f2caaefSJames Feist         {
1191b9d36b47SEd Tanous             output.emplace_back("PositiveHysteresis", *positiveHysteresis);
119283ff9ab6SJames Feist         }
1193c33a90ecSJames Feist         if (direction)
1194c33a90ecSJames Feist         {
1195c33a90ecSJames Feist             constexpr const std::array<const char*, 2> allowedDirections = {
1196c33a90ecSJames Feist                 "Ceiling", "Floor"};
11973544d2a7SEd Tanous             if (std::ranges::find(allowedDirections, *direction) ==
11983544d2a7SEd Tanous                 allowedDirections.end())
1199c33a90ecSJames Feist             {
1200c33a90ecSJames Feist                 messages::propertyValueTypeError(response->res, "Direction",
1201c33a90ecSJames Feist                                                  *direction);
1202c33a90ecSJames Feist                 return CreatePIDRet::fail;
1203c33a90ecSJames Feist             }
1204b9d36b47SEd Tanous             output.emplace_back("Class", *direction);
1205c33a90ecSJames Feist         }
120683ff9ab6SJames Feist     }
120783ff9ab6SJames Feist     else
120883ff9ab6SJames Feist     {
120962598e31SEd Tanous         BMCWEB_LOG_ERROR("Illegal Type {}", type);
121035a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
121183ff9ab6SJames Feist         return CreatePIDRet::fail;
121283ff9ab6SJames Feist     }
121383ff9ab6SJames Feist     return CreatePIDRet::patch;
121483ff9ab6SJames Feist }
121573df0db0SJames Feist struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
121673df0db0SJames Feist {
12176936afe4SEd Tanous     struct CompletionValues
12186936afe4SEd Tanous     {
12196936afe4SEd Tanous         std::vector<std::string> supportedProfiles;
12206936afe4SEd Tanous         std::string currentProfile;
12216936afe4SEd Tanous         dbus::utility::MapperGetSubTreeResponse subtree;
12226936afe4SEd Tanous     };
122383ff9ab6SJames Feist 
12244e23a444SEd Tanous     explicit GetPIDValues(
12254e23a444SEd Tanous         const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
122623a21a1cSEd Tanous         asyncResp(asyncRespIn)
122773df0db0SJames Feist 
12281214b7e7SGunnar Mills     {}
12299c310685SBorawski.Lukasz 
123073df0db0SJames Feist     void run()
12315b4aa86bSJames Feist     {
123273df0db0SJames Feist         std::shared_ptr<GetPIDValues> self = shared_from_this();
123373df0db0SJames Feist 
123473df0db0SJames Feist         // get all configurations
1235e99073f5SGeorge Liu         constexpr std::array<std::string_view, 4> interfaces = {
1236e99073f5SGeorge Liu             pidConfigurationIface, pidZoneConfigurationIface,
1237e99073f5SGeorge Liu             objectManagerIface, stepwiseConfigurationIface};
1238e99073f5SGeorge Liu         dbus::utility::getSubTree(
1239e99073f5SGeorge Liu             "/", 0, interfaces,
1240b9d36b47SEd Tanous             [self](
1241e99073f5SGeorge Liu                 const boost::system::error_code& ec,
1242b9d36b47SEd Tanous                 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
12435b4aa86bSJames Feist                 if (ec)
12445b4aa86bSJames Feist                 {
124562598e31SEd Tanous                     BMCWEB_LOG_ERROR("{}", ec);
124673df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
124773df0db0SJames Feist                     return;
124873df0db0SJames Feist                 }
12496936afe4SEd Tanous                 self->complete.subtree = subtreeLocal;
1250e99073f5SGeorge Liu             });
125173df0db0SJames Feist 
125273df0db0SJames Feist         // at the same time get the selected profile
1253e99073f5SGeorge Liu         constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1254e99073f5SGeorge Liu             thermalModeIface};
1255e99073f5SGeorge Liu         dbus::utility::getSubTree(
1256e99073f5SGeorge Liu             "/", 0, thermalModeIfaces,
1257b9d36b47SEd Tanous             [self](
1258e99073f5SGeorge Liu                 const boost::system::error_code& ec,
1259b9d36b47SEd Tanous                 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
126023a21a1cSEd Tanous                 if (ec || subtreeLocal.empty())
126173df0db0SJames Feist                 {
126273df0db0SJames Feist                     return;
126373df0db0SJames Feist                 }
126423a21a1cSEd Tanous                 if (subtreeLocal[0].second.size() != 1)
126573df0db0SJames Feist                 {
126673df0db0SJames Feist                     // invalid mapper response, should never happen
126762598e31SEd Tanous                     BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
126873df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
12695b4aa86bSJames Feist                     return;
12705b4aa86bSJames Feist                 }
12715b4aa86bSJames Feist 
127223a21a1cSEd Tanous                 const std::string& path = subtreeLocal[0].first;
127323a21a1cSEd Tanous                 const std::string& owner = subtreeLocal[0].second[0].first;
1274fac6e53bSKrzysztof Grobelny 
1275fac6e53bSKrzysztof Grobelny                 sdbusplus::asio::getAllProperties(
1276bd79bce8SPatrick Williams                     *crow::connections::systemBus, owner, path,
1277bd79bce8SPatrick Williams                     thermalModeIface,
1278168e20c1SEd Tanous                     [path, owner,
12795e7e2dc5SEd Tanous                      self](const boost::system::error_code& ec2,
1280b9d36b47SEd Tanous                            const dbus::utility::DBusPropertiesMap& resp) {
128123a21a1cSEd Tanous                         if (ec2)
128273df0db0SJames Feist                         {
128362598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1284bd79bce8SPatrick Williams                                 "GetPIDValues: Can't get thermalModeIface {}",
1285bd79bce8SPatrick Williams                                 path);
128673df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
128773df0db0SJames Feist                             return;
128873df0db0SJames Feist                         }
1289fac6e53bSKrzysztof Grobelny 
1290271584abSEd Tanous                         const std::string* current = nullptr;
1291271584abSEd Tanous                         const std::vector<std::string>* supported = nullptr;
1292fac6e53bSKrzysztof Grobelny 
1293fac6e53bSKrzysztof Grobelny                         const bool success = sdbusplus::unpackPropertiesNoThrow(
1294bd79bce8SPatrick Williams                             dbus_utils::UnpackErrorPrinter(), resp, "Current",
1295bd79bce8SPatrick Williams                             current, "Supported", supported);
1296fac6e53bSKrzysztof Grobelny 
1297fac6e53bSKrzysztof Grobelny                         if (!success)
129873df0db0SJames Feist                         {
1299002d39b4SEd Tanous                             messages::internalError(self->asyncResp->res);
130073df0db0SJames Feist                             return;
130173df0db0SJames Feist                         }
1302fac6e53bSKrzysztof Grobelny 
130373df0db0SJames Feist                         if (current == nullptr || supported == nullptr)
130473df0db0SJames Feist                         {
130562598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1306bd79bce8SPatrick Williams                                 "GetPIDValues: thermal mode iface invalid {}",
1307bd79bce8SPatrick Williams                                 path);
130873df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
130973df0db0SJames Feist                             return;
131073df0db0SJames Feist                         }
13116936afe4SEd Tanous                         self->complete.currentProfile = *current;
13126936afe4SEd Tanous                         self->complete.supportedProfiles = *supported;
1313fac6e53bSKrzysztof Grobelny                     });
1314e99073f5SGeorge Liu             });
131573df0db0SJames Feist     }
131673df0db0SJames Feist 
13176936afe4SEd Tanous     static void
13186936afe4SEd Tanous         processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
13196936afe4SEd Tanous                            const CompletionValues& completion)
132073df0db0SJames Feist     {
132173df0db0SJames Feist         if (asyncResp->res.result() != boost::beast::http::status::ok)
132273df0db0SJames Feist         {
132373df0db0SJames Feist             return;
132473df0db0SJames Feist         }
13255b4aa86bSJames Feist         // create map of <connection, path to objMgr>>
13266936afe4SEd Tanous         boost::container::flat_map<
13276936afe4SEd Tanous             std::string, std::string, std::less<>,
13286936afe4SEd Tanous             std::vector<std::pair<std::string, std::string>>>
13296936afe4SEd Tanous             objectMgrPaths;
13306936afe4SEd Tanous         boost::container::flat_set<std::string, std::less<>,
13316936afe4SEd Tanous                                    std::vector<std::string>>
13326936afe4SEd Tanous             calledConnections;
13336936afe4SEd Tanous         for (const auto& pathGroup : completion.subtree)
13345b4aa86bSJames Feist         {
13355b4aa86bSJames Feist             for (const auto& connectionGroup : pathGroup.second)
13365b4aa86bSJames Feist             {
13376bce33bcSJames Feist                 auto findConnection =
13386bce33bcSJames Feist                     calledConnections.find(connectionGroup.first);
13396bce33bcSJames Feist                 if (findConnection != calledConnections.end())
13406bce33bcSJames Feist                 {
13416bce33bcSJames Feist                     break;
13426bce33bcSJames Feist                 }
134373df0db0SJames Feist                 for (const std::string& interface : connectionGroup.second)
13445b4aa86bSJames Feist                 {
13455b4aa86bSJames Feist                     if (interface == objectManagerIface)
13465b4aa86bSJames Feist                     {
134773df0db0SJames Feist                         objectMgrPaths[connectionGroup.first] = pathGroup.first;
13485b4aa86bSJames Feist                     }
13495b4aa86bSJames Feist                     // this list is alphabetical, so we
13505b4aa86bSJames Feist                     // should have found the objMgr by now
13515b4aa86bSJames Feist                     if (interface == pidConfigurationIface ||
1352b7a08d04SJames Feist                         interface == pidZoneConfigurationIface ||
1353b7a08d04SJames Feist                         interface == stepwiseConfigurationIface)
13545b4aa86bSJames Feist                     {
13555b4aa86bSJames Feist                         auto findObjMgr =
13565b4aa86bSJames Feist                             objectMgrPaths.find(connectionGroup.first);
13575b4aa86bSJames Feist                         if (findObjMgr == objectMgrPaths.end())
13585b4aa86bSJames Feist                         {
135962598e31SEd Tanous                             BMCWEB_LOG_DEBUG("{}Has no Object Manager",
136062598e31SEd Tanous                                              connectionGroup.first);
13615b4aa86bSJames Feist                             continue;
13625b4aa86bSJames Feist                         }
13636bce33bcSJames Feist 
13646bce33bcSJames Feist                         calledConnections.insert(connectionGroup.first);
13656bce33bcSJames Feist 
136673df0db0SJames Feist                         asyncPopulatePid(findObjMgr->first, findObjMgr->second,
13676936afe4SEd Tanous                                          completion.currentProfile,
13686936afe4SEd Tanous                                          completion.supportedProfiles,
136973df0db0SJames Feist                                          asyncResp);
13705b4aa86bSJames Feist                         break;
13715b4aa86bSJames Feist                     }
13725b4aa86bSJames Feist                 }
13735b4aa86bSJames Feist             }
13745b4aa86bSJames Feist         }
137573df0db0SJames Feist     }
137673df0db0SJames Feist 
13776936afe4SEd Tanous     ~GetPIDValues()
13786936afe4SEd Tanous     {
13796936afe4SEd Tanous         boost::asio::post(crow::connections::systemBus->get_io_context(),
13806936afe4SEd Tanous                           std::bind_front(&processingComplete, asyncResp,
13816936afe4SEd Tanous                                           std::move(complete)));
13826936afe4SEd Tanous     }
13836936afe4SEd Tanous 
1384ecd6a3a2SEd Tanous     GetPIDValues(const GetPIDValues&) = delete;
1385ecd6a3a2SEd Tanous     GetPIDValues(GetPIDValues&&) = delete;
1386ecd6a3a2SEd Tanous     GetPIDValues& operator=(const GetPIDValues&) = delete;
1387ecd6a3a2SEd Tanous     GetPIDValues& operator=(GetPIDValues&&) = delete;
1388ecd6a3a2SEd Tanous 
13898d1b46d7Szhanghch05     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
13906936afe4SEd Tanous     CompletionValues complete;
139173df0db0SJames Feist };
139273df0db0SJames Feist 
139373df0db0SJames Feist struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
139473df0db0SJames Feist {
13959e9b6049SEd Tanous     SetPIDValues(
13969e9b6049SEd Tanous         const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
13979e9b6049SEd Tanous         std::vector<
13989e9b6049SEd Tanous             std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
13999e9b6049SEd Tanous             configurationsIn,
14009e9b6049SEd Tanous         std::optional<std::string>& profileIn) :
1401bd79bce8SPatrick Williams         asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
14029e9b6049SEd Tanous         profile(std::move(profileIn))
14039e9b6049SEd Tanous     {}
1404ecd6a3a2SEd Tanous 
1405ecd6a3a2SEd Tanous     SetPIDValues(const SetPIDValues&) = delete;
1406ecd6a3a2SEd Tanous     SetPIDValues(SetPIDValues&&) = delete;
1407ecd6a3a2SEd Tanous     SetPIDValues& operator=(const SetPIDValues&) = delete;
1408ecd6a3a2SEd Tanous     SetPIDValues& operator=(SetPIDValues&&) = delete;
1409ecd6a3a2SEd Tanous 
141073df0db0SJames Feist     void run()
141173df0db0SJames Feist     {
141273df0db0SJames Feist         if (asyncResp->res.result() != boost::beast::http::status::ok)
141373df0db0SJames Feist         {
141473df0db0SJames Feist             return;
141573df0db0SJames Feist         }
141673df0db0SJames Feist 
141773df0db0SJames Feist         std::shared_ptr<SetPIDValues> self = shared_from_this();
141873df0db0SJames Feist 
141973df0db0SJames Feist         // todo(james): might make sense to do a mapper call here if this
142073df0db0SJames Feist         // interface gets more traction
14215eb468daSGeorge Liu         sdbusplus::message::object_path objPath(
14225eb468daSGeorge Liu             "/xyz/openbmc_project/inventory");
14235eb468daSGeorge Liu         dbus::utility::getManagedObjects(
14245eb468daSGeorge Liu             "xyz.openbmc_project.EntityManager", objPath,
14255e7e2dc5SEd Tanous             [self](const boost::system::error_code& ec,
1426914e2d5dSEd Tanous                    const dbus::utility::ManagedObjectType& mObj) {
142773df0db0SJames Feist                 if (ec)
142873df0db0SJames Feist                 {
142962598e31SEd Tanous                     BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
143073df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
143173df0db0SJames Feist                     return;
143273df0db0SJames Feist                 }
1433e69d9de2SJames Feist                 const std::array<const char*, 3> configurations = {
1434e69d9de2SJames Feist                     pidConfigurationIface, pidZoneConfigurationIface,
1435e69d9de2SJames Feist                     stepwiseConfigurationIface};
1436e69d9de2SJames Feist 
143714b0b8d5SJames Feist                 for (const auto& [path, object] : mObj)
1438e69d9de2SJames Feist                 {
143914b0b8d5SJames Feist                     for (const auto& [interface, _] : object)
1440e69d9de2SJames Feist                     {
14413544d2a7SEd Tanous                         if (std::ranges::find(configurations, interface) !=
14423544d2a7SEd Tanous                             configurations.end())
1443e69d9de2SJames Feist                         {
144414b0b8d5SJames Feist                             self->objectCount++;
1445e69d9de2SJames Feist                             break;
1446e69d9de2SJames Feist                         }
1447e69d9de2SJames Feist                     }
1448e69d9de2SJames Feist                 }
1449914e2d5dSEd Tanous                 self->managedObj = mObj;
14505eb468daSGeorge Liu             });
145173df0db0SJames Feist 
145273df0db0SJames Feist         // at the same time get the profile information
1453e99073f5SGeorge Liu         constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1454e99073f5SGeorge Liu             thermalModeIface};
1455e99073f5SGeorge Liu         dbus::utility::getSubTree(
1456e99073f5SGeorge Liu             "/", 0, thermalModeIfaces,
1457e99073f5SGeorge Liu             [self](const boost::system::error_code& ec,
1458b9d36b47SEd Tanous                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
145973df0db0SJames Feist                 if (ec || subtree.empty())
146073df0db0SJames Feist                 {
146173df0db0SJames Feist                     return;
146273df0db0SJames Feist                 }
146373df0db0SJames Feist                 if (subtree[0].second.empty())
146473df0db0SJames Feist                 {
146573df0db0SJames Feist                     // invalid mapper response, should never happen
146662598e31SEd Tanous                     BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
146773df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
146873df0db0SJames Feist                     return;
146973df0db0SJames Feist                 }
147073df0db0SJames Feist 
147173df0db0SJames Feist                 const std::string& path = subtree[0].first;
147273df0db0SJames Feist                 const std::string& owner = subtree[0].second[0].first;
1473fac6e53bSKrzysztof Grobelny                 sdbusplus::asio::getAllProperties(
1474bd79bce8SPatrick Williams                     *crow::connections::systemBus, owner, path,
1475bd79bce8SPatrick Williams                     thermalModeIface,
1476bd79bce8SPatrick Williams                     [self, path,
1477bd79bce8SPatrick Williams                      owner](const boost::system::error_code& ec2,
1478b9d36b47SEd Tanous                             const dbus::utility::DBusPropertiesMap& r) {
1479cb13a392SEd Tanous                         if (ec2)
148073df0db0SJames Feist                         {
148162598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1482bd79bce8SPatrick Williams                                 "SetPIDValues: Can't get thermalModeIface {}",
1483bd79bce8SPatrick Williams                                 path);
148473df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
148573df0db0SJames Feist                             return;
148673df0db0SJames Feist                         }
1487271584abSEd Tanous                         const std::string* current = nullptr;
1488271584abSEd Tanous                         const std::vector<std::string>* supported = nullptr;
1489fac6e53bSKrzysztof Grobelny 
1490fac6e53bSKrzysztof Grobelny                         const bool success = sdbusplus::unpackPropertiesNoThrow(
1491bd79bce8SPatrick Williams                             dbus_utils::UnpackErrorPrinter(), r, "Current",
1492bd79bce8SPatrick Williams                             current, "Supported", supported);
1493fac6e53bSKrzysztof Grobelny 
1494fac6e53bSKrzysztof Grobelny                         if (!success)
149573df0db0SJames Feist                         {
1496002d39b4SEd Tanous                             messages::internalError(self->asyncResp->res);
149773df0db0SJames Feist                             return;
149873df0db0SJames Feist                         }
1499fac6e53bSKrzysztof Grobelny 
150073df0db0SJames Feist                         if (current == nullptr || supported == nullptr)
150173df0db0SJames Feist                         {
150262598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1503bd79bce8SPatrick Williams                                 "SetPIDValues: thermal mode iface invalid {}",
1504bd79bce8SPatrick Williams                                 path);
150573df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
150673df0db0SJames Feist                             return;
150773df0db0SJames Feist                         }
150873df0db0SJames Feist                         self->currentProfile = *current;
150973df0db0SJames Feist                         self->supportedProfiles = *supported;
151073df0db0SJames Feist                         self->profileConnection = owner;
151173df0db0SJames Feist                         self->profilePath = path;
1512fac6e53bSKrzysztof Grobelny                     });
1513e99073f5SGeorge Liu             });
151473df0db0SJames Feist     }
151524b2fe81SEd Tanous     void pidSetDone()
151673df0db0SJames Feist     {
151773df0db0SJames Feist         if (asyncResp->res.result() != boost::beast::http::status::ok)
151873df0db0SJames Feist         {
151973df0db0SJames Feist             return;
15205b4aa86bSJames Feist         }
15218d1b46d7Szhanghch05         std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
152273df0db0SJames Feist         if (profile)
152373df0db0SJames Feist         {
15243544d2a7SEd Tanous             if (std::ranges::find(supportedProfiles, *profile) ==
15253544d2a7SEd Tanous                 supportedProfiles.end())
152673df0db0SJames Feist             {
152773df0db0SJames Feist                 messages::actionParameterUnknown(response->res, "Profile",
152873df0db0SJames Feist                                                  *profile);
152973df0db0SJames Feist                 return;
153073df0db0SJames Feist             }
153173df0db0SJames Feist             currentProfile = *profile;
15329ae226faSGeorge Liu             sdbusplus::asio::setProperty(
15339ae226faSGeorge Liu                 *crow::connections::systemBus, profileConnection, profilePath,
15349ae226faSGeorge Liu                 thermalModeIface, "Current", *profile,
15355e7e2dc5SEd Tanous                 [response](const boost::system::error_code& ec) {
153673df0db0SJames Feist                     if (ec)
153773df0db0SJames Feist                     {
153862598e31SEd Tanous                         BMCWEB_LOG_ERROR("Error patching profile{}", ec);
153973df0db0SJames Feist                         messages::internalError(response->res);
154073df0db0SJames Feist                     }
15419ae226faSGeorge Liu                 });
154273df0db0SJames Feist         }
154373df0db0SJames Feist 
154473df0db0SJames Feist         for (auto& containerPair : configuration)
154573df0db0SJames Feist         {
154673df0db0SJames Feist             auto& container = containerPair.second;
154773df0db0SJames Feist             if (!container)
154873df0db0SJames Feist             {
154973df0db0SJames Feist                 continue;
155073df0db0SJames Feist             }
15516ee7f774SJames Feist 
155202cad96eSEd Tanous             const std::string& type = containerPair.first;
155373df0db0SJames Feist 
15549e9b6049SEd Tanous             for (auto& [name, value] : *container)
155573df0db0SJames Feist             {
1556cddbf3dfSPotin Lai                 std::string dbusObjName = name;
1557cddbf3dfSPotin Lai                 std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
155862598e31SEd Tanous                 BMCWEB_LOG_DEBUG("looking for {}", name);
15596ee7f774SJames Feist 
15603544d2a7SEd Tanous                 auto pathItr = std::ranges::find_if(
15613544d2a7SEd Tanous                     managedObj, [&dbusObjName](const auto& obj) {
156291f75cafSEd Tanous                         return obj.first.filename() == dbusObjName;
156373df0db0SJames Feist                     });
1564b9d36b47SEd Tanous                 dbus::utility::DBusPropertiesMap output;
156573df0db0SJames Feist 
156673df0db0SJames Feist                 output.reserve(16); // The pid interface length
156773df0db0SJames Feist 
156873df0db0SJames Feist                 // determines if we're patching entity-manager or
156973df0db0SJames Feist                 // creating a new object
157073df0db0SJames Feist                 bool createNewObject = (pathItr == managedObj.end());
157162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
15726ee7f774SJames Feist 
157373df0db0SJames Feist                 std::string iface;
1574ea2b670dSEd Tanous                 if (!createNewObject)
1575ea2b670dSEd Tanous                 {
15768be2b5b6SPotin Lai                     bool findInterface = false;
1577ea2b670dSEd Tanous                     for (const auto& interface : pathItr->second)
1578ea2b670dSEd Tanous                     {
1579ea2b670dSEd Tanous                         if (interface.first == pidConfigurationIface)
1580ea2b670dSEd Tanous                         {
1581ea2b670dSEd Tanous                             if (type == "PidControllers" ||
1582ea2b670dSEd Tanous                                 type == "FanControllers")
158373df0db0SJames Feist                             {
158473df0db0SJames Feist                                 iface = pidConfigurationIface;
15858be2b5b6SPotin Lai                                 findInterface = true;
15868be2b5b6SPotin Lai                                 break;
158773df0db0SJames Feist                             }
158873df0db0SJames Feist                         }
1589ea2b670dSEd Tanous                         else if (interface.first == pidZoneConfigurationIface)
159073df0db0SJames Feist                         {
1591ea2b670dSEd Tanous                             if (type == "FanZones")
159273df0db0SJames Feist                             {
1593da39350aSPavanKumarIntel                                 iface = pidZoneConfigurationIface;
15948be2b5b6SPotin Lai                                 findInterface = true;
15958be2b5b6SPotin Lai                                 break;
159673df0db0SJames Feist                             }
159773df0db0SJames Feist                         }
1598ea2b670dSEd Tanous                         else if (interface.first == stepwiseConfigurationIface)
1599ea2b670dSEd Tanous                         {
1600ea2b670dSEd Tanous                             if (type == "StepwiseControllers")
160173df0db0SJames Feist                             {
160273df0db0SJames Feist                                 iface = stepwiseConfigurationIface;
16038be2b5b6SPotin Lai                                 findInterface = true;
16048be2b5b6SPotin Lai                                 break;
16058be2b5b6SPotin Lai                             }
16068be2b5b6SPotin Lai                         }
16078be2b5b6SPotin Lai                     }
16088be2b5b6SPotin Lai 
16098be2b5b6SPotin Lai                     // create new object if interface not found
16108be2b5b6SPotin Lai                     if (!findInterface)
16118be2b5b6SPotin Lai                     {
161273df0db0SJames Feist                         createNewObject = true;
161373df0db0SJames Feist                     }
1614ea2b670dSEd Tanous                 }
16156ee7f774SJames Feist 
16169e9b6049SEd Tanous                 if (createNewObject && value == nullptr)
16176ee7f774SJames Feist                 {
16184e0453b1SGunnar Mills                     // can't delete a non-existent object
16199e9b6049SEd Tanous                     messages::propertyValueNotInList(response->res, value,
1620e2616cc5SEd Tanous                                                      name);
16216ee7f774SJames Feist                     continue;
16226ee7f774SJames Feist                 }
16236ee7f774SJames Feist 
16246ee7f774SJames Feist                 std::string path;
16256ee7f774SJames Feist                 if (pathItr != managedObj.end())
16266ee7f774SJames Feist                 {
16276ee7f774SJames Feist                     path = pathItr->first.str;
16286ee7f774SJames Feist                 }
16296ee7f774SJames Feist 
163062598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
1631e69d9de2SJames Feist 
1632e69d9de2SJames Feist                 // arbitrary limit to avoid attacks
1633e69d9de2SJames Feist                 constexpr const size_t controllerLimit = 500;
163414b0b8d5SJames Feist                 if (createNewObject && objectCount >= controllerLimit)
1635e69d9de2SJames Feist                 {
1636e69d9de2SJames Feist                     messages::resourceExhaustion(response->res, type);
1637e69d9de2SJames Feist                     continue;
1638e69d9de2SJames Feist                 }
1639a170f275SEd Tanous                 std::string escaped = name;
1640a170f275SEd Tanous                 std::replace(escaped.begin(), escaped.end(), '_', ' ');
1641a170f275SEd Tanous                 output.emplace_back("Name", escaped);
164273df0db0SJames Feist 
164373df0db0SJames Feist                 std::string chassis;
164473df0db0SJames Feist                 CreatePIDRet ret = createPidInterface(
16459e9b6049SEd Tanous                     response, type, name, value, path, managedObj,
16469e9b6049SEd Tanous                     createNewObject, output, chassis, currentProfile);
164773df0db0SJames Feist                 if (ret == CreatePIDRet::fail)
164873df0db0SJames Feist                 {
164973df0db0SJames Feist                     return;
165073df0db0SJames Feist                 }
16513174e4dfSEd Tanous                 if (ret == CreatePIDRet::del)
165273df0db0SJames Feist                 {
165373df0db0SJames Feist                     continue;
165473df0db0SJames Feist                 }
165573df0db0SJames Feist 
165673df0db0SJames Feist                 if (!createNewObject)
165773df0db0SJames Feist                 {
165873df0db0SJames Feist                     for (const auto& property : output)
165973df0db0SJames Feist                     {
16607a696974SPotin Lai                         crow::connections::systemBus->async_method_call(
166173df0db0SJames Feist                             [response,
166273df0db0SJames Feist                              propertyName{std::string(property.first)}](
16635e7e2dc5SEd Tanous                                 const boost::system::error_code& ec) {
166473df0db0SJames Feist                                 if (ec)
166573df0db0SJames Feist                                 {
166662598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Error patching {}: {}",
166762598e31SEd Tanous                                                      propertyName, ec);
166873df0db0SJames Feist                                     messages::internalError(response->res);
166973df0db0SJames Feist                                     return;
167073df0db0SJames Feist                                 }
167173df0db0SJames Feist                                 messages::success(response->res);
16727a696974SPotin Lai                             },
16737a696974SPotin Lai                             "xyz.openbmc_project.EntityManager", path,
16747a696974SPotin Lai                             "org.freedesktop.DBus.Properties", "Set", iface,
16757a696974SPotin Lai                             property.first, property.second);
167673df0db0SJames Feist                     }
167773df0db0SJames Feist                 }
167873df0db0SJames Feist                 else
167973df0db0SJames Feist                 {
168073df0db0SJames Feist                     if (chassis.empty())
168173df0db0SJames Feist                     {
168262598e31SEd Tanous                         BMCWEB_LOG_ERROR("Failed to get chassis from config");
1683ace85d60SEd Tanous                         messages::internalError(response->res);
168473df0db0SJames Feist                         return;
168573df0db0SJames Feist                     }
168673df0db0SJames Feist 
168773df0db0SJames Feist                     bool foundChassis = false;
168873df0db0SJames Feist                     for (const auto& obj : managedObj)
168973df0db0SJames Feist                     {
169091f75cafSEd Tanous                         if (obj.first.filename() == chassis)
169173df0db0SJames Feist                         {
169273df0db0SJames Feist                             chassis = obj.first.str;
169373df0db0SJames Feist                             foundChassis = true;
169473df0db0SJames Feist                             break;
169573df0db0SJames Feist                         }
169673df0db0SJames Feist                     }
169773df0db0SJames Feist                     if (!foundChassis)
169873df0db0SJames Feist                     {
169962598e31SEd Tanous                         BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
170073df0db0SJames Feist                         messages::resourceMissingAtURI(
1701ace85d60SEd Tanous                             response->res,
1702ef4c65b7SEd Tanous                             boost::urls::format("/redfish/v1/Chassis/{}",
1703ef4c65b7SEd Tanous                                                 chassis));
170473df0db0SJames Feist                         return;
170573df0db0SJames Feist                     }
170673df0db0SJames Feist 
170773df0db0SJames Feist                     crow::connections::systemBus->async_method_call(
17085e7e2dc5SEd Tanous                         [response](const boost::system::error_code& ec) {
170973df0db0SJames Feist                             if (ec)
171073df0db0SJames Feist                             {
1711bd79bce8SPatrick Williams                                 BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
1712bd79bce8SPatrick Williams                                                  ec);
171373df0db0SJames Feist                                 messages::internalError(response->res);
171473df0db0SJames Feist                                 return;
171573df0db0SJames Feist                             }
171673df0db0SJames Feist                             messages::success(response->res);
171773df0db0SJames Feist                         },
171873df0db0SJames Feist                         "xyz.openbmc_project.EntityManager", chassis,
171973df0db0SJames Feist                         "xyz.openbmc_project.AddObject", "AddObject", output);
172073df0db0SJames Feist                 }
172173df0db0SJames Feist             }
172273df0db0SJames Feist         }
172373df0db0SJames Feist     }
172424b2fe81SEd Tanous 
172524b2fe81SEd Tanous     ~SetPIDValues()
172624b2fe81SEd Tanous     {
172724b2fe81SEd Tanous         try
172824b2fe81SEd Tanous         {
172924b2fe81SEd Tanous             pidSetDone();
173024b2fe81SEd Tanous         }
173124b2fe81SEd Tanous         catch (...)
173224b2fe81SEd Tanous         {
173362598e31SEd Tanous             BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
173424b2fe81SEd Tanous         }
173524b2fe81SEd Tanous     }
173624b2fe81SEd Tanous 
17378d1b46d7Szhanghch05     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
17389e9b6049SEd Tanous     std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
173973df0db0SJames Feist         configuration;
174073df0db0SJames Feist     std::optional<std::string> profile;
174173df0db0SJames Feist     dbus::utility::ManagedObjectType managedObj;
174273df0db0SJames Feist     std::vector<std::string> supportedProfiles;
174373df0db0SJames Feist     std::string currentProfile;
174473df0db0SJames Feist     std::string profileConnection;
174573df0db0SJames Feist     std::string profilePath;
174614b0b8d5SJames Feist     size_t objectCount = 0;
174773df0db0SJames Feist };
174873df0db0SJames Feist 
1749071d8fdfSSunnySrivastava1984 /**
1750071d8fdfSSunnySrivastava1984  * @brief Retrieves BMC manager location data over DBus
1751071d8fdfSSunnySrivastava1984  *
1752ac106bf6SEd Tanous  * @param[in] asyncResp Shared pointer for completing asynchronous calls
1753071d8fdfSSunnySrivastava1984  * @param[in] connectionName - service name
1754071d8fdfSSunnySrivastava1984  * @param[in] path - object path
1755071d8fdfSSunnySrivastava1984  * @return none
1756071d8fdfSSunnySrivastava1984  */
1757ac106bf6SEd Tanous inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1758071d8fdfSSunnySrivastava1984                         const std::string& connectionName,
1759071d8fdfSSunnySrivastava1984                         const std::string& path)
1760071d8fdfSSunnySrivastava1984 {
176162598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get BMC manager Location data.");
1762071d8fdfSSunnySrivastava1984 
17631e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
17641e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
17651e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
1766ac106bf6SEd Tanous         [asyncResp](const boost::system::error_code& ec,
17671e1e598dSJonathan Doman                     const std::string& property) {
1768071d8fdfSSunnySrivastava1984             if (ec)
1769071d8fdfSSunnySrivastava1984             {
177062598e31SEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error for "
177162598e31SEd Tanous                                  "Location");
1772ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
1773071d8fdfSSunnySrivastava1984                 return;
1774071d8fdfSSunnySrivastava1984             }
1775071d8fdfSSunnySrivastava1984 
1776bd79bce8SPatrick Williams             asyncResp->res
1777bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
17781e1e598dSJonathan Doman                 property;
17791e1e598dSJonathan Doman         });
1780071d8fdfSSunnySrivastava1984 }
17817e860f15SJohn Edward Broadbent // avoid name collision systems.hpp
17827e860f15SJohn Edward Broadbent inline void
1783ac106bf6SEd Tanous     managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
17844bf2b033SGunnar Mills {
178562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time");
17864bf2b033SGunnar Mills 
17871e1e598dSJonathan Doman     sdbusplus::asio::getProperty<uint64_t>(
17881e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.BMC",
17891e1e598dSJonathan Doman         "/xyz/openbmc_project/state/bmc0", "xyz.openbmc_project.State.BMC",
17901e1e598dSJonathan Doman         "LastRebootTime",
1791ac106bf6SEd Tanous         [asyncResp](const boost::system::error_code& ec,
17921e1e598dSJonathan Doman                     const uint64_t lastResetTime) {
17934bf2b033SGunnar Mills             if (ec)
17944bf2b033SGunnar Mills             {
179562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
17964bf2b033SGunnar Mills                 return;
17974bf2b033SGunnar Mills             }
17984bf2b033SGunnar Mills 
17994bf2b033SGunnar Mills             // LastRebootTime is epoch time, in milliseconds
18004bf2b033SGunnar Mills             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
18011e1e598dSJonathan Doman             uint64_t lastResetTimeStamp = lastResetTime / 1000;
18024bf2b033SGunnar Mills 
18034bf2b033SGunnar Mills             // Convert to ISO 8601 standard
1804ac106bf6SEd Tanous             asyncResp->res.jsonValue["LastResetTime"] =
18052b82937eSEd Tanous                 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
18061e1e598dSJonathan Doman         });
18074bf2b033SGunnar Mills }
18084bf2b033SGunnar Mills 
18094bfefa74SGunnar Mills /**
18104bfefa74SGunnar Mills  * @brief Set the running firmware image
18114bfefa74SGunnar Mills  *
1812ac106bf6SEd Tanous  * @param[i,o] asyncResp - Async response object
18134bfefa74SGunnar Mills  * @param[i] runningFirmwareTarget - Image to make the running image
18144bfefa74SGunnar Mills  *
18154bfefa74SGunnar Mills  * @return void
18164bfefa74SGunnar Mills  */
18177e860f15SJohn Edward Broadbent inline void
1818ac106bf6SEd Tanous     setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1819f23b7296SEd Tanous                            const std::string& runningFirmwareTarget)
18204bfefa74SGunnar Mills {
18214bfefa74SGunnar Mills     // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1822f23b7296SEd Tanous     std::string::size_type idPos = runningFirmwareTarget.rfind('/');
18234bfefa74SGunnar Mills     if (idPos == std::string::npos)
18244bfefa74SGunnar Mills     {
1825ac106bf6SEd Tanous         messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
18264bfefa74SGunnar Mills                                          "@odata.id");
182762598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
18284bfefa74SGunnar Mills         return;
18294bfefa74SGunnar Mills     }
18304bfefa74SGunnar Mills     idPos++;
18314bfefa74SGunnar Mills     if (idPos >= runningFirmwareTarget.size())
18324bfefa74SGunnar Mills     {
1833ac106bf6SEd Tanous         messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
18344bfefa74SGunnar Mills                                          "@odata.id");
183562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid firmware ID.");
18364bfefa74SGunnar Mills         return;
18374bfefa74SGunnar Mills     }
18384bfefa74SGunnar Mills     std::string firmwareId = runningFirmwareTarget.substr(idPos);
18394bfefa74SGunnar Mills 
18404bfefa74SGunnar Mills     // Make sure the image is valid before setting priority
18415eb468daSGeorge Liu     sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
18425eb468daSGeorge Liu     dbus::utility::getManagedObjects(
18435eb468daSGeorge Liu         "xyz.openbmc_project.Software.BMC.Updater", objPath,
18445eb468daSGeorge Liu         [asyncResp, firmwareId, runningFirmwareTarget](
18455eb468daSGeorge Liu             const boost::system::error_code& ec,
18465eb468daSGeorge Liu             const dbus::utility::ManagedObjectType& subtree) {
18474bfefa74SGunnar Mills             if (ec)
18484bfefa74SGunnar Mills             {
184962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
1850ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
18514bfefa74SGunnar Mills                 return;
18524bfefa74SGunnar Mills             }
18534bfefa74SGunnar Mills 
185426f6976fSEd Tanous             if (subtree.empty())
18554bfefa74SGunnar Mills             {
185662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't find image!");
1857ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
18584bfefa74SGunnar Mills                 return;
18594bfefa74SGunnar Mills             }
18604bfefa74SGunnar Mills 
18614bfefa74SGunnar Mills             bool foundImage = false;
186202cad96eSEd Tanous             for (const auto& object : subtree)
18634bfefa74SGunnar Mills             {
18644bfefa74SGunnar Mills                 const std::string& path =
18654bfefa74SGunnar Mills                     static_cast<const std::string&>(object.first);
1866f23b7296SEd Tanous                 std::size_t idPos2 = path.rfind('/');
18674bfefa74SGunnar Mills 
18684bfefa74SGunnar Mills                 if (idPos2 == std::string::npos)
18694bfefa74SGunnar Mills                 {
18704bfefa74SGunnar Mills                     continue;
18714bfefa74SGunnar Mills                 }
18724bfefa74SGunnar Mills 
18734bfefa74SGunnar Mills                 idPos2++;
18744bfefa74SGunnar Mills                 if (idPos2 >= path.size())
18754bfefa74SGunnar Mills                 {
18764bfefa74SGunnar Mills                     continue;
18774bfefa74SGunnar Mills                 }
18784bfefa74SGunnar Mills 
18794bfefa74SGunnar Mills                 if (path.substr(idPos2) == firmwareId)
18804bfefa74SGunnar Mills                 {
18814bfefa74SGunnar Mills                     foundImage = true;
18824bfefa74SGunnar Mills                     break;
18834bfefa74SGunnar Mills                 }
18844bfefa74SGunnar Mills             }
18854bfefa74SGunnar Mills 
18864bfefa74SGunnar Mills             if (!foundImage)
18874bfefa74SGunnar Mills             {
1888ac106bf6SEd Tanous                 messages::propertyValueNotInList(
1889ac106bf6SEd Tanous                     asyncResp->res, runningFirmwareTarget, "@odata.id");
189062598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
18914bfefa74SGunnar Mills                 return;
18924bfefa74SGunnar Mills             }
18934bfefa74SGunnar Mills 
189462598e31SEd Tanous             BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
189562598e31SEd Tanous                              firmwareId);
18964bfefa74SGunnar Mills 
18974bfefa74SGunnar Mills             // Only support Immediate
18984bfefa74SGunnar Mills             // An addition could be a Redfish Setting like
18994bfefa74SGunnar Mills             // ActiveSoftwareImageApplyTime and support OnReset
19009ae226faSGeorge Liu             sdbusplus::asio::setProperty(
19019ae226faSGeorge Liu                 *crow::connections::systemBus,
19029ae226faSGeorge Liu                 "xyz.openbmc_project.Software.BMC.Updater",
19039ae226faSGeorge Liu                 "/xyz/openbmc_project/software/" + firmwareId,
19049ae226faSGeorge Liu                 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
19059ae226faSGeorge Liu                 static_cast<uint8_t>(0),
1906ac106bf6SEd Tanous                 [asyncResp](const boost::system::error_code& ec2) {
19078a592810SEd Tanous                     if (ec2)
19084bfefa74SGunnar Mills                     {
190962598e31SEd Tanous                         BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1910ac106bf6SEd Tanous                         messages::internalError(asyncResp->res);
19114bfefa74SGunnar Mills                         return;
19124bfefa74SGunnar Mills                     }
1913ac106bf6SEd Tanous                     doBMCGracefulRestart(asyncResp);
19149ae226faSGeorge Liu                 });
19155eb468daSGeorge Liu         });
19164bfefa74SGunnar Mills }
19174bfefa74SGunnar Mills 
1918bd79bce8SPatrick Williams inline void afterSetDateTime(
1919bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1920bd79bce8SPatrick Williams     const boost::system::error_code& ec, const sdbusplus::message_t& msg)
1921c51afd54SEd Tanous {
1922c51afd54SEd Tanous     if (ec)
1923c51afd54SEd Tanous     {
1924c51afd54SEd Tanous         BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1925c51afd54SEd Tanous                          ec);
1926c51afd54SEd Tanous         const sd_bus_error* dbusError = msg.get_error();
1927c51afd54SEd Tanous         if (dbusError != nullptr)
1928c51afd54SEd Tanous         {
1929c51afd54SEd Tanous             std::string_view errorName(dbusError->name);
1930c51afd54SEd Tanous             if (errorName ==
1931c51afd54SEd Tanous                 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1932c51afd54SEd Tanous             {
1933c51afd54SEd Tanous                 BMCWEB_LOG_DEBUG("Setting conflict");
1934c51afd54SEd Tanous                 messages::propertyValueConflict(
1935c51afd54SEd Tanous                     asyncResp->res, "DateTime",
1936c51afd54SEd Tanous                     "Managers/NetworkProtocol/NTPProcotolEnabled");
1937c51afd54SEd Tanous                 return;
1938c51afd54SEd Tanous             }
1939c51afd54SEd Tanous         }
1940c51afd54SEd Tanous         messages::internalError(asyncResp->res);
1941c51afd54SEd Tanous         return;
1942c51afd54SEd Tanous     }
1943c51afd54SEd Tanous     asyncResp->res.result(boost::beast::http::status::no_content);
1944c51afd54SEd Tanous }
1945c51afd54SEd Tanous 
1946c51afd54SEd Tanous inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1947c51afd54SEd Tanous                         const std::string& datetime)
1948af5d6058SSantosh Puranik {
194962598e31SEd Tanous     BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
1950af5d6058SSantosh Puranik 
1951c2e32007SEd Tanous     std::optional<redfish::time_utils::usSinceEpoch> us =
1952c2e32007SEd Tanous         redfish::time_utils::dateStringToEpoch(datetime);
1953c2e32007SEd Tanous     if (!us)
1954af5d6058SSantosh Puranik     {
1955ac106bf6SEd Tanous         messages::propertyValueFormatError(asyncResp->res, datetime,
1956ac106bf6SEd Tanous                                            "DateTime");
1957c2e32007SEd Tanous         return;
1958c2e32007SEd Tanous     }
1959c51afd54SEd Tanous     // Set the absolute datetime
1960c51afd54SEd Tanous     bool relative = false;
1961c51afd54SEd Tanous     bool interactive = false;
1962c51afd54SEd Tanous     crow::connections::systemBus->async_method_call(
1963c51afd54SEd Tanous         [asyncResp](const boost::system::error_code& ec,
1964c51afd54SEd Tanous                     const sdbusplus::message_t& msg) {
1965c51afd54SEd Tanous             afterSetDateTime(asyncResp, ec, msg);
1966c51afd54SEd Tanous         },
1967c51afd54SEd Tanous         "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1968c51afd54SEd Tanous         "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1969c51afd54SEd Tanous         interactive);
197083ff9ab6SJames Feist }
19719c310685SBorawski.Lukasz 
197275815e5cSEd Tanous inline void
197375815e5cSEd Tanous     checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
197475815e5cSEd Tanous {
197575815e5cSEd Tanous     sdbusplus::asio::getProperty<std::string>(
197675815e5cSEd Tanous         *crow::connections::systemBus, "org.freedesktop.systemd1",
197775815e5cSEd Tanous         "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
197875815e5cSEd Tanous         "org.freedesktop.systemd1.Unit", "ActiveState",
197975815e5cSEd Tanous         [asyncResp](const boost::system::error_code& ec,
198075815e5cSEd Tanous                     const std::string& val) {
198175815e5cSEd Tanous             if (!ec)
198275815e5cSEd Tanous             {
198375815e5cSEd Tanous                 if (val == "active")
198475815e5cSEd Tanous                 {
1985539d8c6bSEd Tanous                     asyncResp->res.jsonValue["Status"]["Health"] =
1986539d8c6bSEd Tanous                         resource::Health::Critical;
1987539d8c6bSEd Tanous                     asyncResp->res.jsonValue["Status"]["State"] =
1988539d8c6bSEd Tanous                         resource::State::Quiesced;
198975815e5cSEd Tanous                     return;
199075815e5cSEd Tanous                 }
199175815e5cSEd Tanous             }
1992539d8c6bSEd Tanous             asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
1993bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Status"]["State"] =
1994bd79bce8SPatrick Williams                 resource::State::Enabled;
199575815e5cSEd Tanous         });
199675815e5cSEd Tanous }
199775815e5cSEd Tanous 
19987e860f15SJohn Edward Broadbent inline void requestRoutesManager(App& app)
19997e860f15SJohn Edward Broadbent {
20007e860f15SJohn Edward Broadbent     std::string uuid = persistent_data::getConfig().systemUuid;
20019c310685SBorawski.Lukasz 
2002253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
2003ed398213SEd Tanous         .privileges(redfish::privileges::getManager)
2004bd79bce8SPatrick Williams         .methods(
2005bd79bce8SPatrick Williams             boost::beast::http::verb::
2006bd79bce8SPatrick Williams                 get)([&app,
2007bd79bce8SPatrick Williams                       uuid](const crow::Request& req,
2008253f11b8SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2009253f11b8SEd Tanous                             const std::string& managerId) {
20103ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
201145ca1b86SEd Tanous             {
201245ca1b86SEd Tanous                 return;
201345ca1b86SEd Tanous             }
2014253f11b8SEd Tanous 
2015253f11b8SEd Tanous             if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2016253f11b8SEd Tanous             {
2017bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Manager",
2018bd79bce8SPatrick Williams                                            managerId);
2019253f11b8SEd Tanous                 return;
2020253f11b8SEd Tanous             }
2021253f11b8SEd Tanous 
2022253f11b8SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2023253f11b8SEd Tanous                 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2024bd79bce8SPatrick Williams             asyncResp->res.jsonValue["@odata.type"] =
2025bd79bce8SPatrick Williams                 "#Manager.v1_14_0.Manager";
2026253f11b8SEd Tanous             asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
20277e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
20287e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Description"] =
20297e860f15SJohn Edward Broadbent                 "Baseboard Management Controller";
2030539d8c6bSEd Tanous             asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
20311476687dSEd Tanous 
2032539d8c6bSEd Tanous             asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
20337e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
20347e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2035bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Model"] =
2036bd79bce8SPatrick Williams                 "OpenBmc"; // TODO(ed), get model
20377e860f15SJohn Edward Broadbent 
20381476687dSEd Tanous             asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2039253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
2040253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20411476687dSEd Tanous             asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2042253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2043253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20441476687dSEd Tanous             asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2045bd79bce8SPatrick Williams                 boost::urls::format(
2046bd79bce8SPatrick Williams                     "/redfish/v1/Managers/{}/EthernetInterfaces",
2047253f11b8SEd Tanous                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20487e860f15SJohn Edward Broadbent 
204925b54dbaSEd Tanous             if constexpr (BMCWEB_VM_NBDPROXY)
205036c0f2a3SEd Tanous             {
20511476687dSEd Tanous                 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2052253f11b8SEd Tanous                     boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2053253f11b8SEd Tanous                                         BMCWEB_REDFISH_MANAGER_URI_NAME);
205436c0f2a3SEd Tanous             }
20557e860f15SJohn Edward Broadbent 
20567e860f15SJohn Edward Broadbent             // default oem data
20577e860f15SJohn Edward Broadbent             nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
20587e860f15SJohn Edward Broadbent             nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2059bd79bce8SPatrick Williams             oem["@odata.id"] =
2060bd79bce8SPatrick Williams                 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2061253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
2062fc1cdd14SEd Tanous             oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2063253f11b8SEd Tanous             oemOpenbmc["@odata.id"] =
2064253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2065253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20661476687dSEd Tanous 
20671476687dSEd Tanous             nlohmann::json::object_t certificates;
2068253f11b8SEd Tanous             certificates["@odata.id"] = boost::urls::format(
2069253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Truststore/Certificates",
2070253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
20711476687dSEd Tanous             oemOpenbmc["Certificates"] = std::move(certificates);
20727e860f15SJohn Edward Broadbent 
20737e860f15SJohn Edward Broadbent             // Manager.Reset (an action) can be many values, OpenBMC only
20747e860f15SJohn Edward Broadbent             // supports BMC reboot.
20757e860f15SJohn Edward Broadbent             nlohmann::json& managerReset =
20767e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2077bd79bce8SPatrick Williams             managerReset["target"] = boost::urls::format(
2078bd79bce8SPatrick Williams                 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2079253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
20807e860f15SJohn Edward Broadbent             managerReset["@Redfish.ActionInfo"] =
2081253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2082253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20837e860f15SJohn Edward Broadbent 
20847e860f15SJohn Edward Broadbent             // ResetToDefaults (Factory Reset) has values like
20857e860f15SJohn Edward Broadbent             // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
20867e860f15SJohn Edward Broadbent             // on OpenBMC
20877e860f15SJohn Edward Broadbent             nlohmann::json& resetToDefaults =
20887e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2089253f11b8SEd Tanous             resetToDefaults["target"] = boost::urls::format(
2090253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2091253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
2092613dabeaSEd Tanous             resetToDefaults["ResetType@Redfish.AllowableValues"] =
2093613dabeaSEd Tanous                 nlohmann::json::array_t({"ResetAll"});
20947e860f15SJohn Edward Broadbent 
20957c8c4058STejas Patil             std::pair<std::string, std::string> redfishDateTimeOffset =
20962b82937eSEd Tanous                 redfish::time_utils::getDateTimeOffsetNow();
20977c8c4058STejas Patil 
20987c8c4058STejas Patil             asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
20997c8c4058STejas Patil             asyncResp->res.jsonValue["DateTimeLocalOffset"] =
21007c8c4058STejas Patil                 redfishDateTimeOffset.second;
21017e860f15SJohn Edward Broadbent 
21020e8ac5e7SGunnar Mills             // TODO (Gunnar): Remove these one day since moved to ComputerSystem
21030e8ac5e7SGunnar Mills             // Still used by OCP profiles
21040e8ac5e7SGunnar Mills             // https://github.com/opencomputeproject/OCP-Profiles/issues/23
21057e860f15SJohn Edward Broadbent             // Fill in SerialConsole info
21067e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["SerialConsole"]["ServiceEnabled"] = true;
2107bd79bce8SPatrick Williams             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2108bd79bce8SPatrick Williams                 15;
2109613dabeaSEd Tanous             asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] =
2110613dabeaSEd Tanous                 nlohmann::json::array_t({"IPMI", "SSH"});
211125b54dbaSEd Tanous             if constexpr (BMCWEB_KVM)
211225b54dbaSEd Tanous             {
21137e860f15SJohn Edward Broadbent                 // Fill in GraphicalConsole info
211425b54dbaSEd Tanous                 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
211525b54dbaSEd Tanous                     true;
211625b54dbaSEd Tanous                 asyncResp->res
211725b54dbaSEd Tanous                     .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
211825b54dbaSEd Tanous                 asyncResp->res
211925b54dbaSEd Tanous                     .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2120613dabeaSEd Tanous                     nlohmann::json::array_t({"KVMIP"});
212125b54dbaSEd Tanous             }
212225b54dbaSEd Tanous             if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
21237f3e84a1SEd Tanous             {
2124bd79bce8SPatrick Williams                 asyncResp->res
2125bd79bce8SPatrick Williams                     .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
21261476687dSEd Tanous 
21271476687dSEd Tanous                 nlohmann::json::array_t managerForServers;
21281476687dSEd Tanous                 nlohmann::json::object_t manager;
2129bd79bce8SPatrick Williams                 manager["@odata.id"] = std::format(
2130bd79bce8SPatrick Williams                     "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2131ad539545SPatrick Williams                 managerForServers.emplace_back(std::move(manager));
21321476687dSEd Tanous 
21331476687dSEd Tanous                 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
21341476687dSEd Tanous                     std::move(managerForServers);
21357f3e84a1SEd Tanous             }
21367e860f15SJohn Edward Broadbent 
2137eee0013eSWilly Tu             sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
21387e860f15SJohn Edward Broadbent                                                  "FirmwareVersion", true);
21397e860f15SJohn Edward Broadbent 
21407e860f15SJohn Edward Broadbent             managerGetLastResetTime(asyncResp);
21417e860f15SJohn Edward Broadbent 
2142a51fc2d2SSui Chen             // ManagerDiagnosticData is added for all BMCs.
2143a51fc2d2SSui Chen             nlohmann::json& managerDiagnosticData =
2144a51fc2d2SSui Chen                 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2145bd79bce8SPatrick Williams             managerDiagnosticData["@odata.id"] = boost::urls::format(
2146bd79bce8SPatrick Williams                 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2147253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
2148a51fc2d2SSui Chen 
214925b54dbaSEd Tanous             if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
215025b54dbaSEd Tanous             {
21517e860f15SJohn Edward Broadbent                 auto pids = std::make_shared<GetPIDValues>(asyncResp);
21527e860f15SJohn Edward Broadbent                 pids->run();
215325b54dbaSEd Tanous             }
21547e860f15SJohn Edward Broadbent 
2155bd79bce8SPatrick Williams             getMainChassisId(asyncResp, [](const std::string& chassisId,
2156bd79bce8SPatrick Williams                                            const std::shared_ptr<
2157bd79bce8SPatrick Williams                                                bmcweb::AsyncResp>& aRsp) {
2158bd79bce8SPatrick Williams                 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2159bd79bce8SPatrick Williams                     1;
21601476687dSEd Tanous                 nlohmann::json::array_t managerForChassis;
21618a592810SEd Tanous                 nlohmann::json::object_t managerObj;
2162ef4c65b7SEd Tanous                 boost::urls::url chassiUrl =
2163ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2164eddfc437SWilly Tu                 managerObj["@odata.id"] = chassiUrl;
2165ad539545SPatrick Williams                 managerForChassis.emplace_back(std::move(managerObj));
21661476687dSEd Tanous                 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
21671476687dSEd Tanous                     std::move(managerForChassis);
21681476687dSEd Tanous                 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2169eddfc437SWilly Tu                     chassiUrl;
21707e860f15SJohn Edward Broadbent             });
21717e860f15SJohn Edward Broadbent 
21721e1e598dSJonathan Doman             sdbusplus::asio::getProperty<double>(
21731e1e598dSJonathan Doman                 *crow::connections::systemBus, "org.freedesktop.systemd1",
2174002d39b4SEd Tanous                 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
2175002d39b4SEd Tanous                 "Progress",
217675815e5cSEd Tanous                 [asyncResp](const boost::system::error_code& ec, double val) {
21777e860f15SJohn Edward Broadbent                     if (ec)
21781abe55efSEd Tanous                     {
217962598e31SEd Tanous                         BMCWEB_LOG_ERROR("Error while getting progress");
21807e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
21817e860f15SJohn Edward Broadbent                         return;
21827e860f15SJohn Edward Broadbent                     }
21831e1e598dSJonathan Doman                     if (val < 1.0)
21847e860f15SJohn Edward Broadbent                     {
2185539d8c6bSEd Tanous                         asyncResp->res.jsonValue["Status"]["Health"] =
2186539d8c6bSEd Tanous                             resource::Health::OK;
2187539d8c6bSEd Tanous                         asyncResp->res.jsonValue["Status"]["State"] =
2188539d8c6bSEd Tanous                             resource::State::Starting;
218975815e5cSEd Tanous                         return;
21907e860f15SJohn Edward Broadbent                     }
219175815e5cSEd Tanous                     checkForQuiesced(asyncResp);
21921e1e598dSJonathan Doman                 });
21939c310685SBorawski.Lukasz 
2194e99073f5SGeorge Liu             constexpr std::array<std::string_view, 1> interfaces = {
2195e99073f5SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Bmc"};
2196e99073f5SGeorge Liu             dbus::utility::getSubTree(
2197e99073f5SGeorge Liu                 "/xyz/openbmc_project/inventory", 0, interfaces,
21987e860f15SJohn Edward Broadbent                 [asyncResp](
2199e99073f5SGeorge Liu                     const boost::system::error_code& ec,
2200b9d36b47SEd Tanous                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
22017e860f15SJohn Edward Broadbent                     if (ec)
22021abe55efSEd Tanous                     {
2203bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG(
2204bd79bce8SPatrick Williams                             "D-Bus response error on GetSubTree {}", ec);
22057e860f15SJohn Edward Broadbent                         return;
22067e860f15SJohn Edward Broadbent                     }
220726f6976fSEd Tanous                     if (subtree.empty())
22087e860f15SJohn Edward Broadbent                     {
220962598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
22107e860f15SJohn Edward Broadbent                         return;
22117e860f15SJohn Edward Broadbent                     }
22127e860f15SJohn Edward Broadbent                     // Assume only 1 bmc D-Bus object
22137e860f15SJohn Edward Broadbent                     // Throw an error if there is more than 1
22147e860f15SJohn Edward Broadbent                     if (subtree.size() > 1)
22157e860f15SJohn Edward Broadbent                     {
221662598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
22177e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
22187e860f15SJohn Edward Broadbent                         return;
22197e860f15SJohn Edward Broadbent                     }
22207e860f15SJohn Edward Broadbent 
2221bd79bce8SPatrick Williams                     if (subtree[0].first.empty() ||
2222bd79bce8SPatrick Williams                         subtree[0].second.size() != 1)
22237e860f15SJohn Edward Broadbent                     {
222462598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
22257e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
22267e860f15SJohn Edward Broadbent                         return;
22277e860f15SJohn Edward Broadbent                     }
22287e860f15SJohn Edward Broadbent 
22297e860f15SJohn Edward Broadbent                     const std::string& path = subtree[0].first;
2230bd79bce8SPatrick Williams                     const std::string& connectionName =
2231bd79bce8SPatrick Williams                         subtree[0].second[0].first;
22327e860f15SJohn Edward Broadbent 
2233bd79bce8SPatrick Williams                     for (const auto& interfaceName :
2234bd79bce8SPatrick Williams                          subtree[0].second[0].second)
22357e860f15SJohn Edward Broadbent                     {
22367e860f15SJohn Edward Broadbent                         if (interfaceName ==
22377e860f15SJohn Edward Broadbent                             "xyz.openbmc_project.Inventory.Decorator.Asset")
22387e860f15SJohn Edward Broadbent                         {
2239fac6e53bSKrzysztof Grobelny                             sdbusplus::asio::getAllProperties(
2240bd79bce8SPatrick Williams                                 *crow::connections::systemBus, connectionName,
2241bd79bce8SPatrick Williams                                 path,
2242fac6e53bSKrzysztof Grobelny                                 "xyz.openbmc_project.Inventory.Decorator.Asset",
2243bd79bce8SPatrick Williams                                 [asyncResp](
2244bd79bce8SPatrick Williams                                     const boost::system::error_code& ec2,
2245b9d36b47SEd Tanous                                     const dbus::utility::DBusPropertiesMap&
22467e860f15SJohn Edward Broadbent                                         propertiesList) {
22478a592810SEd Tanous                                     if (ec2)
22487e860f15SJohn Edward Broadbent                                     {
2249bd79bce8SPatrick Williams                                         BMCWEB_LOG_DEBUG(
2250bd79bce8SPatrick Williams                                             "Can't get bmc asset!");
22517e860f15SJohn Edward Broadbent                                         return;
22527e860f15SJohn Edward Broadbent                                     }
22537e860f15SJohn Edward Broadbent 
2254fac6e53bSKrzysztof Grobelny                                     const std::string* partNumber = nullptr;
2255fac6e53bSKrzysztof Grobelny                                     const std::string* serialNumber = nullptr;
2256fac6e53bSKrzysztof Grobelny                                     const std::string* manufacturer = nullptr;
2257fac6e53bSKrzysztof Grobelny                                     const std::string* model = nullptr;
2258bd79bce8SPatrick Williams                                     const std::string* sparePartNumber =
2259bd79bce8SPatrick Williams                                         nullptr;
2260fac6e53bSKrzysztof Grobelny 
2261bd79bce8SPatrick Williams                                     const bool success =
2262bd79bce8SPatrick Williams                                         sdbusplus::unpackPropertiesNoThrow(
2263bd79bce8SPatrick Williams                                             dbus_utils::UnpackErrorPrinter(),
2264bd79bce8SPatrick Williams                                             propertiesList, "PartNumber",
2265bd79bce8SPatrick Williams                                             partNumber, "SerialNumber",
2266bd79bce8SPatrick Williams                                             serialNumber, "Manufacturer",
2267bd79bce8SPatrick Williams                                             manufacturer, "Model", model,
2268bd79bce8SPatrick Williams                                             "SparePartNumber", sparePartNumber);
2269fac6e53bSKrzysztof Grobelny 
2270fac6e53bSKrzysztof Grobelny                                     if (!success)
22717e860f15SJohn Edward Broadbent                                     {
2272002d39b4SEd Tanous                                         messages::internalError(asyncResp->res);
22737e860f15SJohn Edward Broadbent                                         return;
22747e860f15SJohn Edward Broadbent                                     }
2275fac6e53bSKrzysztof Grobelny 
2276fac6e53bSKrzysztof Grobelny                                     if (partNumber != nullptr)
2277fac6e53bSKrzysztof Grobelny                                     {
2278fac6e53bSKrzysztof Grobelny                                         asyncResp->res.jsonValue["PartNumber"] =
2279fac6e53bSKrzysztof Grobelny                                             *partNumber;
22807e860f15SJohn Edward Broadbent                                     }
2281fac6e53bSKrzysztof Grobelny 
2282fac6e53bSKrzysztof Grobelny                                     if (serialNumber != nullptr)
2283fac6e53bSKrzysztof Grobelny                                     {
2284bd79bce8SPatrick Williams                                         asyncResp->res
2285bd79bce8SPatrick Williams                                             .jsonValue["SerialNumber"] =
2286fac6e53bSKrzysztof Grobelny                                             *serialNumber;
22877e860f15SJohn Edward Broadbent                                     }
2288fac6e53bSKrzysztof Grobelny 
2289fac6e53bSKrzysztof Grobelny                                     if (manufacturer != nullptr)
2290fac6e53bSKrzysztof Grobelny                                     {
2291bd79bce8SPatrick Williams                                         asyncResp->res
2292bd79bce8SPatrick Williams                                             .jsonValue["Manufacturer"] =
2293fac6e53bSKrzysztof Grobelny                                             *manufacturer;
2294fac6e53bSKrzysztof Grobelny                                     }
2295fac6e53bSKrzysztof Grobelny 
2296fac6e53bSKrzysztof Grobelny                                     if (model != nullptr)
2297fac6e53bSKrzysztof Grobelny                                     {
2298bd79bce8SPatrick Williams                                         asyncResp->res.jsonValue["Model"] =
2299bd79bce8SPatrick Williams                                             *model;
2300fac6e53bSKrzysztof Grobelny                                     }
2301fac6e53bSKrzysztof Grobelny 
2302fac6e53bSKrzysztof Grobelny                                     if (sparePartNumber != nullptr)
2303fac6e53bSKrzysztof Grobelny                                     {
2304bd79bce8SPatrick Williams                                         asyncResp->res
2305bd79bce8SPatrick Williams                                             .jsonValue["SparePartNumber"] =
2306fac6e53bSKrzysztof Grobelny                                             *sparePartNumber;
2307fac6e53bSKrzysztof Grobelny                                     }
2308fac6e53bSKrzysztof Grobelny                                 });
23097e860f15SJohn Edward Broadbent                         }
2310bd79bce8SPatrick Williams                         else if (
2311bd79bce8SPatrick Williams                             interfaceName ==
23120fda0f12SGeorge Liu                             "xyz.openbmc_project.Inventory.Decorator.LocationCode")
23137e860f15SJohn Edward Broadbent                         {
23147e860f15SJohn Edward Broadbent                             getLocation(asyncResp, connectionName, path);
23157e860f15SJohn Edward Broadbent                         }
23167e860f15SJohn Edward Broadbent                     }
2317e99073f5SGeorge Liu                 });
23187e860f15SJohn Edward Broadbent         });
23197e860f15SJohn Edward Broadbent 
2320253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
2321ed398213SEd Tanous         .privileges(redfish::privileges::patchManager)
232245ca1b86SEd Tanous         .methods(boost::beast::http::verb::patch)(
232345ca1b86SEd Tanous             [&app](const crow::Request& req,
2324253f11b8SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2325253f11b8SEd Tanous                    const std::string& managerId) {
23263ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
232745ca1b86SEd Tanous                 {
232845ca1b86SEd Tanous                     return;
232945ca1b86SEd Tanous                 }
2330253f11b8SEd Tanous 
2331253f11b8SEd Tanous                 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2332253f11b8SEd Tanous                 {
2333bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Manager",
2334bd79bce8SPatrick Williams                                                managerId);
2335253f11b8SEd Tanous                     return;
2336253f11b8SEd Tanous                 }
2337253f11b8SEd Tanous 
23389e9b6049SEd Tanous                 std::optional<std::string> activeSoftwareImageOdataId;
23397e860f15SJohn Edward Broadbent                 std::optional<std::string> datetime;
23409e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> pidControllers;
23419e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> fanControllers;
23429e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> fanZones;
23439e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> stepwiseControllers;
23449e9b6049SEd Tanous                 std::optional<std::string> profile;
23457e860f15SJohn Edward Broadbent 
2346*afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
2347*afc474aeSMyung Bae                         req, asyncResp->res, //
2348*afc474aeSMyung Bae                         "DateTime", datetime, //
2349*afc474aeSMyung Bae                         "Links/ActiveSoftwareImage/@odata.id",
2350*afc474aeSMyung Bae                         activeSoftwareImageOdataId, //
2351*afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/FanControllers", fanControllers, //
2352*afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/FanZones", fanZones, //
2353*afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/PidControllers", pidControllers, //
2354*afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/Profile", profile, //
2355*afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/StepwiseControllers",
2356*afc474aeSMyung Bae                         stepwiseControllers //
23579e9b6049SEd Tanous                         ))
23587e860f15SJohn Edward Broadbent                 {
23597e860f15SJohn Edward Broadbent                     return;
23607e860f15SJohn Edward Broadbent                 }
23617e860f15SJohn Edward Broadbent 
23629e9b6049SEd Tanous                 if (pidControllers || fanControllers || fanZones ||
23639e9b6049SEd Tanous                     stepwiseControllers || profile)
23647e860f15SJohn Edward Broadbent                 {
236525b54dbaSEd Tanous                     if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
236625b54dbaSEd Tanous                     {
2367bd79bce8SPatrick Williams                         std::vector<
2368bd79bce8SPatrick Williams                             std::pair<std::string,
236925b54dbaSEd Tanous                                       std::optional<nlohmann::json::object_t>>>
23709e9b6049SEd Tanous                             configuration;
23719e9b6049SEd Tanous                         if (pidControllers)
23727e860f15SJohn Edward Broadbent                         {
2373bd79bce8SPatrick Williams                             configuration.emplace_back(
2374bd79bce8SPatrick Williams                                 "PidControllers", std::move(pidControllers));
23757e860f15SJohn Edward Broadbent                         }
23769e9b6049SEd Tanous                         if (fanControllers)
23777e860f15SJohn Edward Broadbent                         {
2378bd79bce8SPatrick Williams                             configuration.emplace_back(
2379bd79bce8SPatrick Williams                                 "FanControllers", std::move(fanControllers));
23807e860f15SJohn Edward Broadbent                         }
23819e9b6049SEd Tanous                         if (fanZones)
23827e860f15SJohn Edward Broadbent                         {
2383bd79bce8SPatrick Williams                             configuration.emplace_back("FanZones",
2384bd79bce8SPatrick Williams                                                        std::move(fanZones));
23859e9b6049SEd Tanous                         }
23869e9b6049SEd Tanous                         if (stepwiseControllers)
23879e9b6049SEd Tanous                         {
2388bd79bce8SPatrick Williams                             configuration.emplace_back(
2389bd79bce8SPatrick Williams                                 "StepwiseControllers",
23909e9b6049SEd Tanous                                 std::move(stepwiseControllers));
23919e9b6049SEd Tanous                         }
23929e9b6049SEd Tanous                         auto pid = std::make_shared<SetPIDValues>(
23939e9b6049SEd Tanous                             asyncResp, std::move(configuration), profile);
23947e860f15SJohn Edward Broadbent                         pid->run();
239525b54dbaSEd Tanous                     }
239625b54dbaSEd Tanous                     else
239725b54dbaSEd Tanous                     {
239854dce7f5SGunnar Mills                         messages::propertyUnknown(asyncResp->res, "Oem");
239954dce7f5SGunnar Mills                         return;
240025b54dbaSEd Tanous                     }
24017e860f15SJohn Edward Broadbent                 }
24029e9b6049SEd Tanous 
24039e9b6049SEd Tanous                 if (activeSoftwareImageOdataId)
24047e860f15SJohn Edward Broadbent                 {
2405bd79bce8SPatrick Williams                     setActiveFirmwareImage(asyncResp,
2406bd79bce8SPatrick Williams                                            *activeSoftwareImageOdataId);
24077e860f15SJohn Edward Broadbent                 }
24087e860f15SJohn Edward Broadbent 
24097e860f15SJohn Edward Broadbent                 if (datetime)
24107e860f15SJohn Edward Broadbent                 {
2411c51afd54SEd Tanous                     setDateTime(asyncResp, *datetime);
24127e860f15SJohn Edward Broadbent                 }
24137e860f15SJohn Edward Broadbent             });
24147e860f15SJohn Edward Broadbent }
24157e860f15SJohn Edward Broadbent 
24167e860f15SJohn Edward Broadbent inline void requestRoutesManagerCollection(App& app)
24177e860f15SJohn Edward Broadbent {
24187e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
2419ed398213SEd Tanous         .privileges(redfish::privileges::getManagerCollection)
24207e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
242145ca1b86SEd Tanous             [&app](const crow::Request& req,
24227e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
24233ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
242445ca1b86SEd Tanous                 {
242545ca1b86SEd Tanous                     return;
242645ca1b86SEd Tanous                 }
242783ff9ab6SJames Feist                 // Collections don't include the static data added by SubRoute
242883ff9ab6SJames Feist                 // because it has a duplicate entry for members
24298d1b46d7Szhanghch05                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
24308d1b46d7Szhanghch05                 asyncResp->res.jsonValue["@odata.type"] =
24318d1b46d7Szhanghch05                     "#ManagerCollection.ManagerCollection";
24328d1b46d7Szhanghch05                 asyncResp->res.jsonValue["Name"] = "Manager Collection";
24338d1b46d7Szhanghch05                 asyncResp->res.jsonValue["Members@odata.count"] = 1;
24341476687dSEd Tanous                 nlohmann::json::array_t members;
24351476687dSEd Tanous                 nlohmann::json& bmc = members.emplace_back();
2436bd79bce8SPatrick Williams                 bmc["@odata.id"] = boost::urls::format(
2437bd79bce8SPatrick Williams                     "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
24381476687dSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(members);
24397e860f15SJohn Edward Broadbent             });
24409c310685SBorawski.Lukasz }
24419c310685SBorawski.Lukasz } // namespace redfish
2442