xref: /openbmc/bmcweb/features/redfish/lib/managers.hpp (revision d27c31e9371385fb83e31cb1c6754b113d2bdf17)
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 
53*d27c31e9SJagpal Singh Gill inline std::string getBMCUpdateServiceName()
54*d27c31e9SJagpal Singh Gill {
55*d27c31e9SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
56*d27c31e9SJagpal Singh Gill     {
57*d27c31e9SJagpal Singh Gill         return "xyz.openbmc_project.Software.Manager";
58*d27c31e9SJagpal Singh Gill     }
59*d27c31e9SJagpal Singh Gill     return "xyz.openbmc_project.Software.BMC.Updater";
60*d27c31e9SJagpal Singh Gill }
61*d27c31e9SJagpal Singh Gill 
62*d27c31e9SJagpal Singh Gill inline std::string getBMCUpdateServicePath()
63*d27c31e9SJagpal Singh Gill {
64*d27c31e9SJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
65*d27c31e9SJagpal Singh Gill     {
66*d27c31e9SJagpal Singh Gill         return "/xyz/openbmc_project/software/bmc";
67*d27c31e9SJagpal Singh Gill     }
68*d27c31e9SJagpal Singh Gill     return "/xyz/openbmc_project/software";
69*d27c31e9SJagpal Singh Gill }
70*d27c31e9SJagpal Singh Gill 
71ed5befbdSJennifer Lee /**
722a5c4407SGunnar Mills  * Function reboots the BMC.
732a5c4407SGunnar Mills  *
742a5c4407SGunnar Mills  * @param[in] asyncResp - Shared pointer for completing asynchronous calls
75ed5befbdSJennifer Lee  */
768d1b46d7Szhanghch05 inline void
778d1b46d7Szhanghch05     doBMCGracefulRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
78ed5befbdSJennifer Lee {
79ed5befbdSJennifer Lee     const char* processName = "xyz.openbmc_project.State.BMC";
80ed5befbdSJennifer Lee     const char* objectPath = "/xyz/openbmc_project/state/bmc0";
81ed5befbdSJennifer Lee     const char* interfaceName = "xyz.openbmc_project.State.BMC";
82ed5befbdSJennifer Lee     const std::string& propertyValue =
83ed5befbdSJennifer Lee         "xyz.openbmc_project.State.BMC.Transition.Reboot";
84ed5befbdSJennifer Lee     const char* destProperty = "RequestedBMCTransition";
85ed5befbdSJennifer Lee 
86ed5befbdSJennifer Lee     // Create the D-Bus variant for D-Bus call.
879ae226faSGeorge Liu     sdbusplus::asio::setProperty(
889ae226faSGeorge Liu         *crow::connections::systemBus, processName, objectPath, interfaceName,
899ae226faSGeorge Liu         destProperty, propertyValue,
905e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec) {
91ed5befbdSJennifer Lee             // Use "Set" method to set the property value.
92ed5befbdSJennifer Lee             if (ec)
93ed5befbdSJennifer Lee             {
9462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
95ed5befbdSJennifer Lee                 messages::internalError(asyncResp->res);
96ed5befbdSJennifer Lee                 return;
97ed5befbdSJennifer Lee             }
98ed5befbdSJennifer Lee 
99ed5befbdSJennifer Lee             messages::success(asyncResp->res);
1009ae226faSGeorge Liu         });
101ed5befbdSJennifer Lee }
1022a5c4407SGunnar Mills 
1038d1b46d7Szhanghch05 inline void
1048d1b46d7Szhanghch05     doBMCForceRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
105f92af389SJayaprakash Mutyala {
106f92af389SJayaprakash Mutyala     const char* processName = "xyz.openbmc_project.State.BMC";
107f92af389SJayaprakash Mutyala     const char* objectPath = "/xyz/openbmc_project/state/bmc0";
108f92af389SJayaprakash Mutyala     const char* interfaceName = "xyz.openbmc_project.State.BMC";
109f92af389SJayaprakash Mutyala     const std::string& propertyValue =
110f92af389SJayaprakash Mutyala         "xyz.openbmc_project.State.BMC.Transition.HardReboot";
111f92af389SJayaprakash Mutyala     const char* destProperty = "RequestedBMCTransition";
112f92af389SJayaprakash Mutyala 
113f92af389SJayaprakash Mutyala     // Create the D-Bus variant for D-Bus call.
1149ae226faSGeorge Liu     sdbusplus::asio::setProperty(
1159ae226faSGeorge Liu         *crow::connections::systemBus, processName, objectPath, interfaceName,
1169ae226faSGeorge Liu         destProperty, propertyValue,
1175e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec) {
118f92af389SJayaprakash Mutyala             // Use "Set" method to set the property value.
119f92af389SJayaprakash Mutyala             if (ec)
120f92af389SJayaprakash Mutyala             {
12162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
122f92af389SJayaprakash Mutyala                 messages::internalError(asyncResp->res);
123f92af389SJayaprakash Mutyala                 return;
124f92af389SJayaprakash Mutyala             }
125f92af389SJayaprakash Mutyala 
126f92af389SJayaprakash Mutyala             messages::success(asyncResp->res);
1279ae226faSGeorge Liu         });
128f92af389SJayaprakash Mutyala }
129f92af389SJayaprakash Mutyala 
1302a5c4407SGunnar Mills /**
1312a5c4407SGunnar Mills  * ManagerResetAction class supports the POST method for the Reset (reboot)
1322a5c4407SGunnar Mills  * action.
1332a5c4407SGunnar Mills  */
1347e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetAction(App& app)
1352a5c4407SGunnar Mills {
1362a5c4407SGunnar Mills     /**
1372a5c4407SGunnar Mills      * Function handles POST method request.
1382a5c4407SGunnar Mills      * Analyzes POST body before sending Reset (Reboot) request data to D-Bus.
139f92af389SJayaprakash Mutyala      * OpenBMC supports ResetType "GracefulRestart" and "ForceRestart".
1402a5c4407SGunnar Mills      */
1417e860f15SJohn Edward Broadbent 
142253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Actions/Manager.Reset/")
143ed398213SEd Tanous         .privileges(redfish::privileges::postManager)
1447e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
14545ca1b86SEd Tanous             [&app](const crow::Request& req,
146253f11b8SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
147253f11b8SEd Tanous                    const std::string& managerId) {
1483ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
14945ca1b86SEd Tanous                 {
15045ca1b86SEd Tanous                     return;
15145ca1b86SEd Tanous                 }
152253f11b8SEd Tanous                 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
153253f11b8SEd Tanous                 {
154bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Manager",
155bd79bce8SPatrick Williams                                                managerId);
156253f11b8SEd Tanous                     return;
157253f11b8SEd Tanous                 }
158253f11b8SEd Tanous 
15962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Post Manager Reset.");
1602a5c4407SGunnar Mills 
1612a5c4407SGunnar Mills                 std::string resetType;
1622a5c4407SGunnar Mills 
16315ed6780SWilly Tu                 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
1647e860f15SJohn Edward Broadbent                                                resetType))
1652a5c4407SGunnar Mills                 {
1662a5c4407SGunnar Mills                     return;
1672a5c4407SGunnar Mills                 }
1682a5c4407SGunnar Mills 
169f92af389SJayaprakash Mutyala                 if (resetType == "GracefulRestart")
170f92af389SJayaprakash Mutyala                 {
17162598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
172f92af389SJayaprakash Mutyala                     doBMCGracefulRestart(asyncResp);
173f92af389SJayaprakash Mutyala                     return;
174f92af389SJayaprakash Mutyala                 }
1753174e4dfSEd Tanous                 if (resetType == "ForceRestart")
176f92af389SJayaprakash Mutyala                 {
17762598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
178f92af389SJayaprakash Mutyala                     doBMCForceRestart(asyncResp);
179f92af389SJayaprakash Mutyala                     return;
180f92af389SJayaprakash Mutyala                 }
181bd79bce8SPatrick Williams                 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
182bd79bce8SPatrick Williams                                  resetType);
1832a5c4407SGunnar Mills                 messages::actionParameterNotSupported(asyncResp->res, resetType,
1842a5c4407SGunnar Mills                                                       "ResetType");
1852a5c4407SGunnar Mills 
1862a5c4407SGunnar Mills                 return;
1877e860f15SJohn Edward Broadbent             });
1882a5c4407SGunnar Mills }
189ed5befbdSJennifer Lee 
1903e40fc74SGunnar Mills /**
1913e40fc74SGunnar Mills  * ManagerResetToDefaultsAction class supports POST method for factory reset
1923e40fc74SGunnar Mills  * action.
1933e40fc74SGunnar Mills  */
1947e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetToDefaultsAction(App& app)
1953e40fc74SGunnar Mills {
1963e40fc74SGunnar Mills     /**
1973e40fc74SGunnar Mills      * Function handles ResetToDefaults POST method request.
1983e40fc74SGunnar Mills      *
1993e40fc74SGunnar Mills      * Analyzes POST body message and factory resets BMC by calling
2003e40fc74SGunnar Mills      * BMC code updater factory reset followed by a BMC reboot.
2013e40fc74SGunnar Mills      *
2023e40fc74SGunnar Mills      * BMC code updater factory reset wipes the whole BMC read-write
2033e40fc74SGunnar Mills      * filesystem which includes things like the network settings.
2043e40fc74SGunnar Mills      *
2053e40fc74SGunnar Mills      * OpenBMC only supports ResetToDefaultsType "ResetAll".
2063e40fc74SGunnar Mills      */
2077e860f15SJohn Edward Broadbent 
2087e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
209253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Actions/Manager.ResetToDefaults/")
210ed398213SEd Tanous         .privileges(redfish::privileges::postManager)
211bd79bce8SPatrick Williams         .methods(
212bd79bce8SPatrick Williams             boost::beast::http::verb::
213bd79bce8SPatrick Williams                 post)([&app](
214bd79bce8SPatrick Williams                           const crow::Request& req,
215253f11b8SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
216253f11b8SEd Tanous                           const std::string& managerId) {
2173ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
21845ca1b86SEd Tanous             {
21945ca1b86SEd Tanous                 return;
22045ca1b86SEd Tanous             }
221253f11b8SEd Tanous 
222253f11b8SEd Tanous             if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
223253f11b8SEd Tanous             {
224bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Manager",
225bd79bce8SPatrick Williams                                            managerId);
226253f11b8SEd Tanous                 return;
227253f11b8SEd Tanous             }
228253f11b8SEd Tanous 
22962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Post ResetToDefaults.");
2303e40fc74SGunnar Mills 
2319970e93fSKonstantin Aladyshev             std::optional<std::string> resetType;
2329970e93fSKonstantin Aladyshev             std::optional<std::string> resetToDefaultsType;
2333e40fc74SGunnar Mills 
234afc474aeSMyung Bae             if (!json_util::readJsonAction( //
235afc474aeSMyung Bae                     req, asyncResp->res, //
236afc474aeSMyung Bae                     "ResetToDefaultsType", resetToDefaultsType, //
237afc474aeSMyung Bae                     "ResetType", resetType //
238afc474aeSMyung Bae                     ))
2393e40fc74SGunnar Mills             {
2409970e93fSKonstantin Aladyshev                 BMCWEB_LOG_DEBUG("Missing property ResetType.");
2413e40fc74SGunnar Mills 
242bd79bce8SPatrick Williams                 messages::actionParameterMissing(
243bd79bce8SPatrick Williams                     asyncResp->res, "ResetToDefaults", "ResetType");
2443e40fc74SGunnar Mills                 return;
2453e40fc74SGunnar Mills             }
2463e40fc74SGunnar Mills 
2479970e93fSKonstantin Aladyshev             if (resetToDefaultsType && !resetType)
2489970e93fSKonstantin Aladyshev             {
2499970e93fSKonstantin Aladyshev                 BMCWEB_LOG_WARNING(
2509970e93fSKonstantin Aladyshev                     "Using deprecated ResetToDefaultsType, should be ResetType."
2519970e93fSKonstantin Aladyshev                     "Support for the ResetToDefaultsType will be dropped in 2Q24");
2529970e93fSKonstantin Aladyshev                 resetType = resetToDefaultsType;
2539970e93fSKonstantin Aladyshev             }
2549970e93fSKonstantin Aladyshev 
2553e40fc74SGunnar Mills             if (resetType != "ResetAll")
2563e40fc74SGunnar Mills             {
2579970e93fSKonstantin Aladyshev                 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
2589970e93fSKonstantin Aladyshev                                  *resetType);
259bd79bce8SPatrick Williams                 messages::actionParameterNotSupported(asyncResp->res,
260bd79bce8SPatrick Williams                                                       *resetType, "ResetType");
2613e40fc74SGunnar Mills                 return;
2623e40fc74SGunnar Mills             }
2633e40fc74SGunnar Mills 
2643e40fc74SGunnar Mills             crow::connections::systemBus->async_method_call(
2655e7e2dc5SEd Tanous                 [asyncResp](const boost::system::error_code& ec) {
2663e40fc74SGunnar Mills                     if (ec)
2673e40fc74SGunnar Mills                     {
26862598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec);
2693e40fc74SGunnar Mills                         messages::internalError(asyncResp->res);
2703e40fc74SGunnar Mills                         return;
2713e40fc74SGunnar Mills                     }
2723e40fc74SGunnar Mills                     // Factory Reset doesn't actually happen until a reboot
2733e40fc74SGunnar Mills                     // Can't erase what the BMC is running on
2743e40fc74SGunnar Mills                     doBMCGracefulRestart(asyncResp);
2753e40fc74SGunnar Mills                 },
276*d27c31e9SJagpal Singh Gill                 getBMCUpdateServiceName(), getBMCUpdateServicePath(),
2773e40fc74SGunnar Mills                 "xyz.openbmc_project.Common.FactoryReset", "Reset");
2787e860f15SJohn Edward Broadbent         });
2793e40fc74SGunnar Mills }
2803e40fc74SGunnar Mills 
2811cb1a9e6SAppaRao Puli /**
2821cb1a9e6SAppaRao Puli  * ManagerResetActionInfo derived class for delivering Manager
2831cb1a9e6SAppaRao Puli  * ResetType AllowableValues using ResetInfo schema.
2841cb1a9e6SAppaRao Puli  */
2857e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetActionInfo(App& app)
2861cb1a9e6SAppaRao Puli {
2871cb1a9e6SAppaRao Puli     /**
2881cb1a9e6SAppaRao Puli      * Functions triggers appropriate requests on DBus
2891cb1a9e6SAppaRao Puli      */
2907e860f15SJohn Edward Broadbent 
291253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/")
292ed398213SEd Tanous         .privileges(redfish::privileges::getActionInfo)
2937e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
29445ca1b86SEd Tanous             [&app](const crow::Request& req,
295253f11b8SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
296253f11b8SEd Tanous                    const std::string& managerId) {
2973ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
29845ca1b86SEd Tanous                 {
29945ca1b86SEd Tanous                     return;
30045ca1b86SEd Tanous                 }
3011476687dSEd Tanous 
302253f11b8SEd Tanous                 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
303253f11b8SEd Tanous                 {
304bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Manager",
305bd79bce8SPatrick Williams                                                managerId);
306253f11b8SEd Tanous                     return;
307253f11b8SEd Tanous                 }
308253f11b8SEd Tanous 
3091476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
3101476687dSEd Tanous                     "#ActionInfo.v1_1_2.ActionInfo";
311bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
312bd79bce8SPatrick Williams                     "/redfish/v1/Managers/{}/ResetActionInfo",
313253f11b8SEd Tanous                     BMCWEB_REDFISH_MANAGER_URI_NAME);
3141476687dSEd Tanous                 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3151476687dSEd Tanous                 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3161476687dSEd Tanous                 nlohmann::json::object_t parameter;
3171476687dSEd Tanous                 parameter["Name"] = "ResetType";
3181476687dSEd Tanous                 parameter["Required"] = true;
319539d8c6bSEd Tanous                 parameter["DataType"] = action_info::ParameterTypes::String;
3201476687dSEd Tanous 
3211476687dSEd Tanous                 nlohmann::json::array_t allowableValues;
322ad539545SPatrick Williams                 allowableValues.emplace_back("GracefulRestart");
323ad539545SPatrick Williams                 allowableValues.emplace_back("ForceRestart");
3241476687dSEd Tanous                 parameter["AllowableValues"] = std::move(allowableValues);
3251476687dSEd Tanous 
3261476687dSEd Tanous                 nlohmann::json::array_t parameters;
327ad539545SPatrick Williams                 parameters.emplace_back(std::move(parameter));
3281476687dSEd Tanous 
3291476687dSEd Tanous                 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3307e860f15SJohn Edward Broadbent             });
3311cb1a9e6SAppaRao Puli }
3321cb1a9e6SAppaRao Puli 
3335b4aa86bSJames Feist static constexpr const char* objectManagerIface =
3345b4aa86bSJames Feist     "org.freedesktop.DBus.ObjectManager";
3355b4aa86bSJames Feist static constexpr const char* pidConfigurationIface =
3365b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid";
3375b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface =
3385b4aa86bSJames Feist     "xyz.openbmc_project.Configuration.Pid.Zone";
339b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface =
340b7a08d04SJames Feist     "xyz.openbmc_project.Configuration.Stepwise";
34173df0db0SJames Feist static constexpr const char* thermalModeIface =
34273df0db0SJames Feist     "xyz.openbmc_project.Control.ThermalMode";
3439c310685SBorawski.Lukasz 
3448d1b46d7Szhanghch05 inline void
3458d1b46d7Szhanghch05     asyncPopulatePid(const std::string& connection, const std::string& path,
34673df0db0SJames Feist                      const std::string& currentProfile,
34773df0db0SJames Feist                      const std::vector<std::string>& supportedProfiles,
3488d1b46d7Szhanghch05                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3495b4aa86bSJames Feist {
3505eb468daSGeorge Liu     sdbusplus::message::object_path objPath(path);
3515eb468daSGeorge Liu     dbus::utility::getManagedObjects(
3525eb468daSGeorge Liu         connection, objPath,
35373df0db0SJames Feist         [asyncResp, currentProfile, supportedProfiles](
3545e7e2dc5SEd Tanous             const boost::system::error_code& ec,
3555b4aa86bSJames Feist             const dbus::utility::ManagedObjectType& managedObj) {
3565b4aa86bSJames Feist             if (ec)
3575b4aa86bSJames Feist             {
35862598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec);
359f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
3605b4aa86bSJames Feist                 return;
3615b4aa86bSJames Feist             }
3625b4aa86bSJames Feist             nlohmann::json& configRoot =
3635b4aa86bSJames Feist                 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
3645b4aa86bSJames Feist             nlohmann::json& fans = configRoot["FanControllers"];
365bd79bce8SPatrick Williams             fans["@odata.type"] =
366bd79bce8SPatrick Williams                 "#OpenBMCManager.v1_0_0.Manager.FanControllers";
367253f11b8SEd Tanous             fans["@odata.id"] = boost::urls::format(
368253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
369253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
3705b4aa86bSJames Feist 
3715b4aa86bSJames Feist             nlohmann::json& pids = configRoot["PidControllers"];
372bd79bce8SPatrick Williams             pids["@odata.type"] =
373bd79bce8SPatrick Williams                 "#OpenBMCManager.v1_0_0.Manager.PidControllers";
374253f11b8SEd Tanous             pids["@odata.id"] = boost::urls::format(
375253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
376253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
3775b4aa86bSJames Feist 
378b7a08d04SJames Feist             nlohmann::json& stepwise = configRoot["StepwiseControllers"];
379fc1cdd14SEd Tanous             stepwise["@odata.type"] =
380fc1cdd14SEd Tanous                 "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
381253f11b8SEd Tanous             stepwise["@odata.id"] = boost::urls::format(
382253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
383253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
384b7a08d04SJames Feist 
3855b4aa86bSJames Feist             nlohmann::json& zones = configRoot["FanZones"];
386253f11b8SEd Tanous             zones["@odata.id"] = boost::urls::format(
387253f11b8SEd Tanous                 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
388253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
389fc1cdd14SEd Tanous             zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
390253f11b8SEd Tanous             configRoot["@odata.id"] =
391253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
392253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
393fc1cdd14SEd Tanous             configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
39473df0db0SJames Feist             configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
39573df0db0SJames Feist 
39673df0db0SJames Feist             if (!currentProfile.empty())
39773df0db0SJames Feist             {
39873df0db0SJames Feist                 configRoot["Profile"] = currentProfile;
39973df0db0SJames Feist             }
400bf2ddedeSCarson Labrado             BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
4015b4aa86bSJames Feist 
4025b4aa86bSJames Feist             for (const auto& pathPair : managedObj)
4035b4aa86bSJames Feist             {
4045b4aa86bSJames Feist                 for (const auto& intfPair : pathPair.second)
4055b4aa86bSJames Feist                 {
4065b4aa86bSJames Feist                     if (intfPair.first != pidConfigurationIface &&
407b7a08d04SJames Feist                         intfPair.first != pidZoneConfigurationIface &&
408b7a08d04SJames Feist                         intfPair.first != stepwiseConfigurationIface)
4095b4aa86bSJames Feist                     {
4105b4aa86bSJames Feist                         continue;
4115b4aa86bSJames Feist                     }
41273df0db0SJames Feist 
413711ac7a9SEd Tanous                     std::string name;
414711ac7a9SEd Tanous 
415711ac7a9SEd Tanous                     for (const std::pair<std::string,
416bd79bce8SPatrick Williams                                          dbus::utility::DbusVariantType>&
417bd79bce8SPatrick Williams                              propPair : intfPair.second)
418711ac7a9SEd Tanous                     {
419711ac7a9SEd Tanous                         if (propPair.first == "Name")
420711ac7a9SEd Tanous                         {
4215b4aa86bSJames Feist                             const std::string* namePtr =
422711ac7a9SEd Tanous                                 std::get_if<std::string>(&propPair.second);
4235b4aa86bSJames Feist                             if (namePtr == nullptr)
4245b4aa86bSJames Feist                             {
42562598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Pid Name Field illegal");
426b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
4275b4aa86bSJames Feist                                 return;
4285b4aa86bSJames Feist                             }
429db697703SWilly Tu                             name = *namePtr;
4305b4aa86bSJames Feist                             dbus::utility::escapePathForDbus(name);
431711ac7a9SEd Tanous                         }
432711ac7a9SEd Tanous                         else if (propPair.first == "Profiles")
43373df0db0SJames Feist                         {
43473df0db0SJames Feist                             const std::vector<std::string>* profiles =
43573df0db0SJames Feist                                 std::get_if<std::vector<std::string>>(
436711ac7a9SEd Tanous                                     &propPair.second);
43773df0db0SJames Feist                             if (profiles == nullptr)
43873df0db0SJames Feist                             {
43962598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
44073df0db0SJames Feist                                 messages::internalError(asyncResp->res);
44173df0db0SJames Feist                                 return;
44273df0db0SJames Feist                             }
44373df0db0SJames Feist                             if (std::find(profiles->begin(), profiles->end(),
44473df0db0SJames Feist                                           currentProfile) == profiles->end())
44573df0db0SJames Feist                             {
44662598e31SEd Tanous                                 BMCWEB_LOG_INFO(
447bd79bce8SPatrick Williams                                     "{} not supported in current profile",
448bd79bce8SPatrick Williams                                     name);
44973df0db0SJames Feist                                 continue;
45073df0db0SJames Feist                             }
45173df0db0SJames Feist                         }
452711ac7a9SEd Tanous                     }
453b7a08d04SJames Feist                     nlohmann::json* config = nullptr;
454c33a90ecSJames Feist                     const std::string* classPtr = nullptr;
455711ac7a9SEd Tanous 
456711ac7a9SEd Tanous                     for (const std::pair<std::string,
457bd79bce8SPatrick Williams                                          dbus::utility::DbusVariantType>&
458bd79bce8SPatrick Williams                              propPair : intfPair.second)
459c33a90ecSJames Feist                     {
460727dc83fSLei YU                         if (propPair.first == "Class")
461711ac7a9SEd Tanous                         {
462bd79bce8SPatrick Williams                             classPtr =
463bd79bce8SPatrick Williams                                 std::get_if<std::string>(&propPair.second);
464711ac7a9SEd Tanous                         }
465c33a90ecSJames Feist                     }
466c33a90ecSJames Feist 
467253f11b8SEd Tanous                     boost::urls::url url(
468253f11b8SEd Tanous                         boost::urls::format("/redfish/v1/Managers/{}",
469253f11b8SEd Tanous                                             BMCWEB_REDFISH_MANAGER_URI_NAME));
4705b4aa86bSJames Feist                     if (intfPair.first == pidZoneConfigurationIface)
4715b4aa86bSJames Feist                     {
4725b4aa86bSJames Feist                         std::string chassis;
473bd79bce8SPatrick Williams                         if (!dbus::utility::getNthStringFromPath(
474bd79bce8SPatrick Williams                                 pathPair.first.str, 5, chassis))
4755b4aa86bSJames Feist                         {
4765b4aa86bSJames Feist                             chassis = "#IllegalValue";
4775b4aa86bSJames Feist                         }
4785b4aa86bSJames Feist                         nlohmann::json& zone = zones[name];
479bd79bce8SPatrick Williams                         zone["Chassis"]["@odata.id"] = boost::urls::format(
480bd79bce8SPatrick Williams                             "/redfish/v1/Chassis/{}", chassis);
481eddfc437SWilly Tu                         url.set_fragment(
482eddfc437SWilly Tu                             ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
483eddfc437SWilly Tu                                 .to_string());
484eddfc437SWilly Tu                         zone["@odata.id"] = std::move(url);
485fc1cdd14SEd Tanous                         zone["@odata.type"] =
486fc1cdd14SEd Tanous                             "#OpenBMCManager.v1_0_0.Manager.FanZone";
487b7a08d04SJames Feist                         config = &zone;
4885b4aa86bSJames Feist                     }
4895b4aa86bSJames Feist 
490b7a08d04SJames Feist                     else if (intfPair.first == stepwiseConfigurationIface)
4915b4aa86bSJames Feist                     {
492c33a90ecSJames Feist                         if (classPtr == nullptr)
493c33a90ecSJames Feist                         {
49462598e31SEd Tanous                             BMCWEB_LOG_ERROR("Pid Class Field illegal");
495c33a90ecSJames Feist                             messages::internalError(asyncResp->res);
496c33a90ecSJames Feist                             return;
497c33a90ecSJames Feist                         }
498c33a90ecSJames Feist 
499b7a08d04SJames Feist                         nlohmann::json& controller = stepwise[name];
500b7a08d04SJames Feist                         config = &controller;
501eddfc437SWilly Tu                         url.set_fragment(
502eddfc437SWilly Tu                             ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
503eddfc437SWilly Tu                              name)
504eddfc437SWilly Tu                                 .to_string());
505eddfc437SWilly Tu                         controller["@odata.id"] = std::move(url);
506b7a08d04SJames Feist                         controller["@odata.type"] =
507fc1cdd14SEd Tanous                             "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
508b7a08d04SJames Feist 
509c33a90ecSJames Feist                         controller["Direction"] = *classPtr;
5105b4aa86bSJames Feist                     }
5115b4aa86bSJames Feist 
5125b4aa86bSJames Feist                     // pid and fans are off the same configuration
513b7a08d04SJames Feist                     else if (intfPair.first == pidConfigurationIface)
5145b4aa86bSJames Feist                     {
5155b4aa86bSJames Feist                         if (classPtr == nullptr)
5165b4aa86bSJames Feist                         {
51762598e31SEd Tanous                             BMCWEB_LOG_ERROR("Pid Class Field illegal");
518a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
5195b4aa86bSJames Feist                             return;
5205b4aa86bSJames Feist                         }
5215b4aa86bSJames Feist                         bool isFan = *classPtr == "fan";
522bd79bce8SPatrick Williams                         nlohmann::json& element =
523bd79bce8SPatrick Williams                             isFan ? fans[name] : pids[name];
524b7a08d04SJames Feist                         config = &element;
5255b4aa86bSJames Feist                         if (isFan)
5265b4aa86bSJames Feist                         {
527eddfc437SWilly Tu                             url.set_fragment(
528eddfc437SWilly Tu                                 ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
529eddfc437SWilly Tu                                  name)
530eddfc437SWilly Tu                                     .to_string());
531eddfc437SWilly Tu                             element["@odata.id"] = std::move(url);
532fc1cdd14SEd Tanous                             element["@odata.type"] =
533fc1cdd14SEd Tanous                                 "#OpenBMCManager.v1_0_0.Manager.FanController";
5345b4aa86bSJames Feist                         }
5355b4aa86bSJames Feist                         else
5365b4aa86bSJames Feist                         {
537eddfc437SWilly Tu                             url.set_fragment(
538eddfc437SWilly Tu                                 ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
539eddfc437SWilly Tu                                  name)
540eddfc437SWilly Tu                                     .to_string());
541eddfc437SWilly Tu                             element["@odata.id"] = std::move(url);
542fc1cdd14SEd Tanous                             element["@odata.type"] =
543fc1cdd14SEd Tanous                                 "#OpenBMCManager.v1_0_0.Manager.PidController";
5445b4aa86bSJames Feist                         }
545b7a08d04SJames Feist                     }
546b7a08d04SJames Feist                     else
547b7a08d04SJames Feist                     {
54862598e31SEd Tanous                         BMCWEB_LOG_ERROR("Unexpected configuration");
549b7a08d04SJames Feist                         messages::internalError(asyncResp->res);
550b7a08d04SJames Feist                         return;
551b7a08d04SJames Feist                     }
552b7a08d04SJames Feist 
553b7a08d04SJames Feist                     // used for making maps out of 2 vectors
554b7a08d04SJames Feist                     const std::vector<double>* keys = nullptr;
555b7a08d04SJames Feist                     const std::vector<double>* values = nullptr;
556b7a08d04SJames Feist 
557b7a08d04SJames Feist                     for (const auto& propertyPair : intfPair.second)
558b7a08d04SJames Feist                     {
559b7a08d04SJames Feist                         if (propertyPair.first == "Type" ||
560b7a08d04SJames Feist                             propertyPair.first == "Class" ||
561b7a08d04SJames Feist                             propertyPair.first == "Name")
562b7a08d04SJames Feist                         {
563b7a08d04SJames Feist                             continue;
564b7a08d04SJames Feist                         }
565b7a08d04SJames Feist 
566b7a08d04SJames Feist                         // zones
567b7a08d04SJames Feist                         if (intfPair.first == pidZoneConfigurationIface)
568b7a08d04SJames Feist                         {
569b7a08d04SJames Feist                             const double* ptr =
570abf2add6SEd Tanous                                 std::get_if<double>(&propertyPair.second);
571b7a08d04SJames Feist                             if (ptr == nullptr)
572b7a08d04SJames Feist                             {
57362598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Field Illegal {}",
57462598e31SEd Tanous                                                  propertyPair.first);
575b7a08d04SJames Feist                                 messages::internalError(asyncResp->res);
576b7a08d04SJames Feist                                 return;
577b7a08d04SJames Feist                             }
578b7a08d04SJames Feist                             (*config)[propertyPair.first] = *ptr;
579b7a08d04SJames Feist                         }
580b7a08d04SJames Feist 
581b7a08d04SJames Feist                         if (intfPair.first == stepwiseConfigurationIface)
582b7a08d04SJames Feist                         {
583b7a08d04SJames Feist                             if (propertyPair.first == "Reading" ||
584b7a08d04SJames Feist                                 propertyPair.first == "Output")
585b7a08d04SJames Feist                             {
586b7a08d04SJames Feist                                 const std::vector<double>* ptr =
587abf2add6SEd Tanous                                     std::get_if<std::vector<double>>(
588b7a08d04SJames Feist                                         &propertyPair.second);
589b7a08d04SJames Feist 
590b7a08d04SJames Feist                                 if (ptr == nullptr)
591b7a08d04SJames Feist                                 {
59262598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
59362598e31SEd Tanous                                                      propertyPair.first);
594b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
595b7a08d04SJames Feist                                     return;
596b7a08d04SJames Feist                                 }
597b7a08d04SJames Feist 
598b7a08d04SJames Feist                                 if (propertyPair.first == "Reading")
599b7a08d04SJames Feist                                 {
600b7a08d04SJames Feist                                     keys = ptr;
601b7a08d04SJames Feist                                 }
602b7a08d04SJames Feist                                 else
603b7a08d04SJames Feist                                 {
604b7a08d04SJames Feist                                     values = ptr;
605b7a08d04SJames Feist                                 }
606e662eae8SEd Tanous                                 if (keys != nullptr && values != nullptr)
607b7a08d04SJames Feist                                 {
608b7a08d04SJames Feist                                     if (keys->size() != values->size())
609b7a08d04SJames Feist                                     {
61062598e31SEd Tanous                                         BMCWEB_LOG_ERROR(
61162598e31SEd Tanous                                             "Reading and Output size don't match ");
612b7a08d04SJames Feist                                         messages::internalError(asyncResp->res);
613b7a08d04SJames Feist                                         return;
614b7a08d04SJames Feist                                     }
615b7a08d04SJames Feist                                     nlohmann::json& steps = (*config)["Steps"];
616b7a08d04SJames Feist                                     steps = nlohmann::json::array();
617b7a08d04SJames Feist                                     for (size_t ii = 0; ii < keys->size(); ii++)
618b7a08d04SJames Feist                                     {
6191476687dSEd Tanous                                         nlohmann::json::object_t step;
6201476687dSEd Tanous                                         step["Target"] = (*keys)[ii];
6211476687dSEd Tanous                                         step["Output"] = (*values)[ii];
622b2ba3072SPatrick Williams                                         steps.emplace_back(std::move(step));
623b7a08d04SJames Feist                                     }
624b7a08d04SJames Feist                                 }
625b7a08d04SJames Feist                             }
626b7a08d04SJames Feist                             if (propertyPair.first == "NegativeHysteresis" ||
627b7a08d04SJames Feist                                 propertyPair.first == "PositiveHysteresis")
628b7a08d04SJames Feist                             {
629b7a08d04SJames Feist                                 const double* ptr =
630abf2add6SEd Tanous                                     std::get_if<double>(&propertyPair.second);
631b7a08d04SJames Feist                                 if (ptr == nullptr)
632b7a08d04SJames Feist                                 {
63362598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
63462598e31SEd Tanous                                                      propertyPair.first);
635b7a08d04SJames Feist                                     messages::internalError(asyncResp->res);
636b7a08d04SJames Feist                                     return;
637b7a08d04SJames Feist                                 }
638b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
639b7a08d04SJames Feist                             }
640b7a08d04SJames Feist                         }
641b7a08d04SJames Feist 
642b7a08d04SJames Feist                         // pid and fans are off the same configuration
643b7a08d04SJames Feist                         if (intfPair.first == pidConfigurationIface ||
644b7a08d04SJames Feist                             intfPair.first == stepwiseConfigurationIface)
645b7a08d04SJames Feist                         {
6465b4aa86bSJames Feist                             if (propertyPair.first == "Zones")
6475b4aa86bSJames Feist                             {
6485b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
649abf2add6SEd Tanous                                     std::get_if<std::vector<std::string>>(
6501b6b96c5SEd Tanous                                         &propertyPair.second);
6515b4aa86bSJames Feist 
6525b4aa86bSJames Feist                                 if (inputs == nullptr)
6535b4aa86bSJames Feist                                 {
65462598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
655a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
6565b4aa86bSJames Feist                                     return;
6575b4aa86bSJames Feist                                 }
658b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
6595b4aa86bSJames Feist                                 data = nlohmann::json::array();
6605b4aa86bSJames Feist                                 for (std::string itemCopy : *inputs)
6615b4aa86bSJames Feist                                 {
6625b4aa86bSJames Feist                                     dbus::utility::escapePathForDbus(itemCopy);
6631476687dSEd Tanous                                     nlohmann::json::object_t input;
664bd79bce8SPatrick Williams                                     boost::urls::url managerUrl =
665bd79bce8SPatrick Williams                                         boost::urls::format(
666253f11b8SEd Tanous                                             "/redfish/v1/Managers/{}#{}",
667253f11b8SEd Tanous                                             BMCWEB_REDFISH_MANAGER_URI_NAME,
668eddfc437SWilly Tu                                             ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
669eddfc437SWilly Tu                                              itemCopy)
670eddfc437SWilly Tu                                                 .to_string());
671eddfc437SWilly Tu                                     input["@odata.id"] = std::move(managerUrl);
672b2ba3072SPatrick Williams                                     data.emplace_back(std::move(input));
6735b4aa86bSJames Feist                                 }
6745b4aa86bSJames Feist                             }
6755b4aa86bSJames Feist                             // todo(james): may never happen, but this
6765b4aa86bSJames Feist                             // assumes configuration data referenced in the
6775b4aa86bSJames Feist                             // PID config is provided by the same daemon, we
6785b4aa86bSJames Feist                             // could add another loop to cover all cases,
6795b4aa86bSJames Feist                             // but I'm okay kicking this can down the road a
6805b4aa86bSJames Feist                             // bit
6815b4aa86bSJames Feist 
6825b4aa86bSJames Feist                             else if (propertyPair.first == "Inputs" ||
6835b4aa86bSJames Feist                                      propertyPair.first == "Outputs")
6845b4aa86bSJames Feist                             {
685b7a08d04SJames Feist                                 auto& data = (*config)[propertyPair.first];
6865b4aa86bSJames Feist                                 const std::vector<std::string>* inputs =
687abf2add6SEd Tanous                                     std::get_if<std::vector<std::string>>(
6881b6b96c5SEd Tanous                                         &propertyPair.second);
6895b4aa86bSJames Feist 
6905b4aa86bSJames Feist                                 if (inputs == nullptr)
6915b4aa86bSJames Feist                                 {
69262598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
69362598e31SEd Tanous                                                      propertyPair.first);
694f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
6955b4aa86bSJames Feist                                     return;
6965b4aa86bSJames Feist                                 }
6975b4aa86bSJames Feist                                 data = *inputs;
698b943aaefSJames Feist                             }
699b943aaefSJames Feist                             else if (propertyPair.first == "SetPointOffset")
700b943aaefSJames Feist                             {
701b943aaefSJames Feist                                 const std::string* ptr =
702bd79bce8SPatrick Williams                                     std::get_if<std::string>(
703bd79bce8SPatrick Williams                                         &propertyPair.second);
704b943aaefSJames Feist 
705b943aaefSJames Feist                                 if (ptr == nullptr)
706b943aaefSJames Feist                                 {
70762598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
70862598e31SEd Tanous                                                      propertyPair.first);
709b943aaefSJames Feist                                     messages::internalError(asyncResp->res);
710b943aaefSJames Feist                                     return;
711b943aaefSJames Feist                                 }
712b943aaefSJames Feist                                 // translate from dbus to redfish
713b943aaefSJames Feist                                 if (*ptr == "WarningHigh")
714b943aaefSJames Feist                                 {
715b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
716b943aaefSJames Feist                                         "UpperThresholdNonCritical";
717b943aaefSJames Feist                                 }
718b943aaefSJames Feist                                 else if (*ptr == "WarningLow")
719b943aaefSJames Feist                                 {
720b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
721b943aaefSJames Feist                                         "LowerThresholdNonCritical";
722b943aaefSJames Feist                                 }
723b943aaefSJames Feist                                 else if (*ptr == "CriticalHigh")
724b943aaefSJames Feist                                 {
725b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
726b943aaefSJames Feist                                         "UpperThresholdCritical";
727b943aaefSJames Feist                                 }
728b943aaefSJames Feist                                 else if (*ptr == "CriticalLow")
729b943aaefSJames Feist                                 {
730b943aaefSJames Feist                                     (*config)["SetPointOffset"] =
731b943aaefSJames Feist                                         "LowerThresholdCritical";
732b943aaefSJames Feist                                 }
733b943aaefSJames Feist                                 else
734b943aaefSJames Feist                                 {
73562598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
736b943aaefSJames Feist                                     messages::internalError(asyncResp->res);
737b943aaefSJames Feist                                     return;
738b943aaefSJames Feist                                 }
739b943aaefSJames Feist                             }
740b943aaefSJames Feist                             // doubles
741bd79bce8SPatrick Williams                             else if (propertyPair.first ==
742bd79bce8SPatrick Williams                                          "FFGainCoefficient" ||
7435b4aa86bSJames Feist                                      propertyPair.first == "FFOffCoefficient" ||
7445b4aa86bSJames Feist                                      propertyPair.first == "ICoefficient" ||
7455b4aa86bSJames Feist                                      propertyPair.first == "ILimitMax" ||
7465b4aa86bSJames Feist                                      propertyPair.first == "ILimitMin" ||
747bd79bce8SPatrick Williams                                      propertyPair.first ==
748bd79bce8SPatrick Williams                                          "PositiveHysteresis" ||
749bd79bce8SPatrick Williams                                      propertyPair.first ==
750bd79bce8SPatrick Williams                                          "NegativeHysteresis" ||
7515b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMax" ||
7525b4aa86bSJames Feist                                      propertyPair.first == "OutLimitMin" ||
7535b4aa86bSJames Feist                                      propertyPair.first == "PCoefficient" ||
7547625cb81SJames Feist                                      propertyPair.first == "SetPoint" ||
7555b4aa86bSJames Feist                                      propertyPair.first == "SlewNeg" ||
7565b4aa86bSJames Feist                                      propertyPair.first == "SlewPos")
7575b4aa86bSJames Feist                             {
7585b4aa86bSJames Feist                                 const double* ptr =
759abf2add6SEd Tanous                                     std::get_if<double>(&propertyPair.second);
7605b4aa86bSJames Feist                                 if (ptr == nullptr)
7615b4aa86bSJames Feist                                 {
76262598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Field Illegal {}",
76362598e31SEd Tanous                                                      propertyPair.first);
764f12894f8SJason M. Bills                                     messages::internalError(asyncResp->res);
7655b4aa86bSJames Feist                                     return;
7665b4aa86bSJames Feist                                 }
767b7a08d04SJames Feist                                 (*config)[propertyPair.first] = *ptr;
7685b4aa86bSJames Feist                             }
7695b4aa86bSJames Feist                         }
7705b4aa86bSJames Feist                     }
7715b4aa86bSJames Feist                 }
7725b4aa86bSJames Feist             }
7735eb468daSGeorge Liu         });
7745b4aa86bSJames Feist }
775ca537928SJennifer Lee 
77683ff9ab6SJames Feist enum class CreatePIDRet
77783ff9ab6SJames Feist {
77883ff9ab6SJames Feist     fail,
77983ff9ab6SJames Feist     del,
78083ff9ab6SJames Feist     patch
78183ff9ab6SJames Feist };
78283ff9ab6SJames Feist 
7838d1b46d7Szhanghch05 inline bool
7848d1b46d7Szhanghch05     getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response,
7859e9b6049SEd Tanous                         std::vector<nlohmann::json::object_t>& config,
7865f2caaefSJames Feist                         std::vector<std::string>& zones)
7875f2caaefSJames Feist {
788b6baeaa4SJames Feist     if (config.empty())
789b6baeaa4SJames Feist     {
79062598e31SEd Tanous         BMCWEB_LOG_ERROR("Empty Zones");
791f818b04dSEd Tanous         messages::propertyValueFormatError(response->res, config, "Zones");
792b6baeaa4SJames Feist         return false;
793b6baeaa4SJames Feist     }
7945f2caaefSJames Feist     for (auto& odata : config)
7955f2caaefSJames Feist     {
7965f2caaefSJames Feist         std::string path;
7979e9b6049SEd Tanous         if (!redfish::json_util::readJsonObject(odata, response->res,
7989e9b6049SEd Tanous                                                 "@odata.id", path))
7995f2caaefSJames Feist         {
8005f2caaefSJames Feist             return false;
8015f2caaefSJames Feist         }
8025f2caaefSJames Feist         std::string input;
80361adbda3SJames Feist 
80461adbda3SJames Feist         // 8 below comes from
80561adbda3SJames Feist         // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
80661adbda3SJames Feist         //     0    1     2      3    4    5      6     7      8
80761adbda3SJames Feist         if (!dbus::utility::getNthStringFromPath(path, 8, input))
8085f2caaefSJames Feist         {
80962598e31SEd Tanous             BMCWEB_LOG_ERROR("Got invalid path {}", path);
81062598e31SEd Tanous             BMCWEB_LOG_ERROR("Illegal Type Zones");
811f818b04dSEd Tanous             messages::propertyValueFormatError(response->res, odata, "Zones");
8125f2caaefSJames Feist             return false;
8135f2caaefSJames Feist         }
814a170f275SEd Tanous         std::replace(input.begin(), input.end(), '_', ' ');
8155f2caaefSJames Feist         zones.emplace_back(std::move(input));
8165f2caaefSJames Feist     }
8175f2caaefSJames Feist     return true;
8185f2caaefSJames Feist }
8195f2caaefSJames Feist 
820711ac7a9SEd Tanous inline const dbus::utility::ManagedObjectType::value_type*
82173df0db0SJames Feist     findChassis(const dbus::utility::ManagedObjectType& managedObj,
8229e9b6049SEd Tanous                 std::string_view value, std::string& chassis)
823b6baeaa4SJames Feist {
82462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
825b6baeaa4SJames Feist 
8269e9b6049SEd Tanous     std::string escaped(value);
8276ce82fabSYaswanth Reddy M     std::replace(escaped.begin(), escaped.end(), ' ', '_');
828b6baeaa4SJames Feist     escaped = "/" + escaped;
8293544d2a7SEd Tanous     auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
83018f8f608SEd Tanous         if (obj.first.str.ends_with(escaped))
831b6baeaa4SJames Feist         {
83262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
833b6baeaa4SJames Feist             return true;
834b6baeaa4SJames Feist         }
835b6baeaa4SJames Feist         return false;
836b6baeaa4SJames Feist     });
837b6baeaa4SJames Feist 
838b6baeaa4SJames Feist     if (it == managedObj.end())
839b6baeaa4SJames Feist     {
84073df0db0SJames Feist         return nullptr;
841b6baeaa4SJames Feist     }
842b6baeaa4SJames Feist     // 5 comes from <chassis-name> being the 5th element
843b6baeaa4SJames Feist     // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
84473df0db0SJames Feist     if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
84573df0db0SJames Feist     {
84673df0db0SJames Feist         return &(*it);
84773df0db0SJames Feist     }
84873df0db0SJames Feist 
84973df0db0SJames Feist     return nullptr;
850b6baeaa4SJames Feist }
851b6baeaa4SJames Feist 
85223a21a1cSEd Tanous inline CreatePIDRet createPidInterface(
8538d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
8549e9b6049SEd Tanous     std::string_view name, nlohmann::json& jsonValue, const std::string& path,
85583ff9ab6SJames Feist     const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
856b9d36b47SEd Tanous     dbus::utility::DBusPropertiesMap& output, std::string& chassis,
857b9d36b47SEd Tanous     const std::string& profile)
85883ff9ab6SJames Feist {
8595f2caaefSJames Feist     // common deleter
8609e9b6049SEd Tanous     if (jsonValue == nullptr)
8615f2caaefSJames Feist     {
8625f2caaefSJames Feist         std::string iface;
8635f2caaefSJames Feist         if (type == "PidControllers" || type == "FanControllers")
8645f2caaefSJames Feist         {
8655f2caaefSJames Feist             iface = pidConfigurationIface;
8665f2caaefSJames Feist         }
8675f2caaefSJames Feist         else if (type == "FanZones")
8685f2caaefSJames Feist         {
8695f2caaefSJames Feist             iface = pidZoneConfigurationIface;
8705f2caaefSJames Feist         }
8715f2caaefSJames Feist         else if (type == "StepwiseControllers")
8725f2caaefSJames Feist         {
8735f2caaefSJames Feist             iface = stepwiseConfigurationIface;
8745f2caaefSJames Feist         }
8755f2caaefSJames Feist         else
8765f2caaefSJames Feist         {
87762598e31SEd Tanous             BMCWEB_LOG_ERROR("Illegal Type {}", type);
8785f2caaefSJames Feist             messages::propertyUnknown(response->res, type);
8795f2caaefSJames Feist             return CreatePIDRet::fail;
8805f2caaefSJames Feist         }
8816ee7f774SJames Feist 
88262598e31SEd Tanous         BMCWEB_LOG_DEBUG("del {} {}", path, iface);
8835f2caaefSJames Feist         // delete interface
8845f2caaefSJames Feist         crow::connections::systemBus->async_method_call(
8855e7e2dc5SEd Tanous             [response, path](const boost::system::error_code& ec) {
8865f2caaefSJames Feist                 if (ec)
8875f2caaefSJames Feist                 {
88862598e31SEd Tanous                     BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
8895f2caaefSJames Feist                     messages::internalError(response->res);
890b6baeaa4SJames Feist                     return;
8915f2caaefSJames Feist                 }
892b6baeaa4SJames Feist                 messages::success(response->res);
8935f2caaefSJames Feist             },
8945f2caaefSJames Feist             "xyz.openbmc_project.EntityManager", path, iface, "Delete");
8955f2caaefSJames Feist         return CreatePIDRet::del;
8965f2caaefSJames Feist     }
8975f2caaefSJames Feist 
898711ac7a9SEd Tanous     const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
899b6baeaa4SJames Feist     if (!createNewObject)
900b6baeaa4SJames Feist     {
901b6baeaa4SJames Feist         // if we aren't creating a new object, we should be able to find it on
902b6baeaa4SJames Feist         // d-bus
9039e9b6049SEd Tanous         managedItem = findChassis(managedObj, name, chassis);
90473df0db0SJames Feist         if (managedItem == nullptr)
905b6baeaa4SJames Feist         {
90662598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
907ef4c65b7SEd Tanous             messages::invalidObject(
908ef4c65b7SEd Tanous                 response->res,
909ef4c65b7SEd Tanous                 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
910b6baeaa4SJames Feist             return CreatePIDRet::fail;
911b6baeaa4SJames Feist         }
912b6baeaa4SJames Feist     }
913b6baeaa4SJames Feist 
91426f6976fSEd Tanous     if (!profile.empty() &&
91573df0db0SJames Feist         (type == "PidControllers" || type == "FanControllers" ||
91673df0db0SJames Feist          type == "StepwiseControllers"))
91773df0db0SJames Feist     {
91873df0db0SJames Feist         if (managedItem == nullptr)
91973df0db0SJames Feist         {
920b9d36b47SEd Tanous             output.emplace_back("Profiles", std::vector<std::string>{profile});
92173df0db0SJames Feist         }
92273df0db0SJames Feist         else
92373df0db0SJames Feist         {
92473df0db0SJames Feist             std::string interface;
92573df0db0SJames Feist             if (type == "StepwiseControllers")
92673df0db0SJames Feist             {
92773df0db0SJames Feist                 interface = stepwiseConfigurationIface;
92873df0db0SJames Feist             }
92973df0db0SJames Feist             else
93073df0db0SJames Feist             {
93173df0db0SJames Feist                 interface = pidConfigurationIface;
93273df0db0SJames Feist             }
933711ac7a9SEd Tanous             bool ifaceFound = false;
934711ac7a9SEd Tanous             for (const auto& iface : managedItem->second)
935711ac7a9SEd Tanous             {
936711ac7a9SEd Tanous                 if (iface.first == interface)
937711ac7a9SEd Tanous                 {
938711ac7a9SEd Tanous                     ifaceFound = true;
939711ac7a9SEd Tanous                     for (const auto& prop : iface.second)
940711ac7a9SEd Tanous                     {
941711ac7a9SEd Tanous                         if (prop.first == "Profiles")
942711ac7a9SEd Tanous                         {
943711ac7a9SEd Tanous                             const std::vector<std::string>* curProfiles =
944711ac7a9SEd Tanous                                 std::get_if<std::vector<std::string>>(
945711ac7a9SEd Tanous                                     &(prop.second));
946711ac7a9SEd Tanous                             if (curProfiles == nullptr)
947711ac7a9SEd Tanous                             {
94862598e31SEd Tanous                                 BMCWEB_LOG_ERROR(
94962598e31SEd Tanous                                     "Illegal profiles in managed object");
950711ac7a9SEd Tanous                                 messages::internalError(response->res);
951711ac7a9SEd Tanous                                 return CreatePIDRet::fail;
952711ac7a9SEd Tanous                             }
953711ac7a9SEd Tanous                             if (std::find(curProfiles->begin(),
954bd79bce8SPatrick Williams                                           curProfiles->end(), profile) ==
955bd79bce8SPatrick Williams                                 curProfiles->end())
956711ac7a9SEd Tanous                             {
957711ac7a9SEd Tanous                                 std::vector<std::string> newProfiles =
958711ac7a9SEd Tanous                                     *curProfiles;
959711ac7a9SEd Tanous                                 newProfiles.push_back(profile);
960b9d36b47SEd Tanous                                 output.emplace_back("Profiles", newProfiles);
961711ac7a9SEd Tanous                             }
962711ac7a9SEd Tanous                         }
963711ac7a9SEd Tanous                     }
964711ac7a9SEd Tanous                 }
965711ac7a9SEd Tanous             }
966711ac7a9SEd Tanous 
967711ac7a9SEd Tanous             if (!ifaceFound)
96873df0db0SJames Feist             {
96962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to find interface in managed object");
97073df0db0SJames Feist                 messages::internalError(response->res);
97173df0db0SJames Feist                 return CreatePIDRet::fail;
97273df0db0SJames Feist             }
97373df0db0SJames Feist         }
97473df0db0SJames Feist     }
97573df0db0SJames Feist 
97683ff9ab6SJames Feist     if (type == "PidControllers" || type == "FanControllers")
97783ff9ab6SJames Feist     {
97883ff9ab6SJames Feist         if (createNewObject)
97983ff9ab6SJames Feist         {
980b9d36b47SEd Tanous             output.emplace_back("Class",
981b9d36b47SEd Tanous                                 type == "PidControllers" ? "temp" : "fan");
982b9d36b47SEd Tanous             output.emplace_back("Type", "Pid");
98383ff9ab6SJames Feist         }
9845f2caaefSJames Feist 
9859e9b6049SEd Tanous         std::optional<std::vector<nlohmann::json::object_t>> zones;
9865f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
9875f2caaefSJames Feist         std::optional<std::vector<std::string>> outputs;
9885f2caaefSJames Feist         std::map<std::string, std::optional<double>> doubles;
989b943aaefSJames Feist         std::optional<std::string> setpointOffset;
990afc474aeSMyung Bae         if (!redfish::json_util::readJson( //
991afc474aeSMyung Bae                 jsonValue, response->res, //
992afc474aeSMyung Bae                 "FFGainCoefficient", doubles["FFGainCoefficient"], //
993afc474aeSMyung Bae                 "FFOffCoefficient", doubles["FFOffCoefficient"], //
994afc474aeSMyung Bae                 "ICoefficient", doubles["ICoefficient"], //
995afc474aeSMyung Bae                 "ILimitMax", doubles["ILimitMax"], //
996afc474aeSMyung Bae                 "ILimitMin", doubles["ILimitMin"], //
997afc474aeSMyung Bae                 "Inputs", inputs, //
998afc474aeSMyung Bae                 "NegativeHysteresis", doubles["NegativeHysteresis"], //
999afc474aeSMyung Bae                 "OutLimitMax", doubles["OutLimitMax"], //
1000afc474aeSMyung Bae                 "OutLimitMin", doubles["OutLimitMin"], //
1001afc474aeSMyung Bae                 "Outputs", outputs, //
1002afc474aeSMyung Bae                 "PCoefficient", doubles["PCoefficient"], //
1003afc474aeSMyung Bae                 "PositiveHysteresis", doubles["PositiveHysteresis"], //
1004afc474aeSMyung Bae                 "SetPoint", doubles["SetPoint"], //
1005afc474aeSMyung Bae                 "SetPointOffset", setpointOffset, //
1006afc474aeSMyung Bae                 "SlewNeg", doubles["SlewNeg"], //
1007afc474aeSMyung Bae                 "SlewPos", doubles["SlewPos"], //
1008afc474aeSMyung Bae                 "Zones", zones //
1009afc474aeSMyung Bae                 ))
101083ff9ab6SJames Feist         {
10115f2caaefSJames Feist             return CreatePIDRet::fail;
101283ff9ab6SJames Feist         }
1013afc474aeSMyung Bae 
10145f2caaefSJames Feist         if (zones)
10155f2caaefSJames Feist         {
10165f2caaefSJames Feist             std::vector<std::string> zonesStr;
10175f2caaefSJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStr))
10185f2caaefSJames Feist             {
101962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Illegal Zones");
10205f2caaefSJames Feist                 return CreatePIDRet::fail;
10215f2caaefSJames Feist             }
1022b6baeaa4SJames Feist             if (chassis.empty() &&
1023e662eae8SEd Tanous                 findChassis(managedObj, zonesStr[0], chassis) == nullptr)
1024b6baeaa4SJames Feist             {
102562598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
1026ace85d60SEd Tanous                 messages::invalidObject(
1027ef4c65b7SEd Tanous                     response->res,
1028ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", chassis));
1029b6baeaa4SJames Feist                 return CreatePIDRet::fail;
1030b6baeaa4SJames Feist             }
1031b9d36b47SEd Tanous             output.emplace_back("Zones", std::move(zonesStr));
10325f2caaefSJames Feist         }
1033afb9ee06SEd Tanous 
1034afb9ee06SEd Tanous         if (inputs)
10355f2caaefSJames Feist         {
1036afb9ee06SEd Tanous             for (std::string& value : *inputs)
103783ff9ab6SJames Feist             {
1038a170f275SEd Tanous                 std::replace(value.begin(), value.end(), '_', ' ');
103983ff9ab6SJames Feist             }
1040afb9ee06SEd Tanous             output.emplace_back("Inputs", *inputs);
1041afb9ee06SEd Tanous         }
1042afb9ee06SEd Tanous 
1043afb9ee06SEd Tanous         if (outputs)
10445f2caaefSJames Feist         {
1045afb9ee06SEd Tanous             for (std::string& value : *outputs)
10465f2caaefSJames Feist             {
1047afb9ee06SEd Tanous                 std::replace(value.begin(), value.end(), '_', ' ');
10485f2caaefSJames Feist             }
1049afb9ee06SEd Tanous             output.emplace_back("Outputs", *outputs);
105083ff9ab6SJames Feist         }
105183ff9ab6SJames Feist 
1052b943aaefSJames Feist         if (setpointOffset)
1053b943aaefSJames Feist         {
1054b943aaefSJames Feist             // translate between redfish and dbus names
1055b943aaefSJames Feist             if (*setpointOffset == "UpperThresholdNonCritical")
1056b943aaefSJames Feist             {
1057b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "WarningLow");
1058b943aaefSJames Feist             }
1059b943aaefSJames Feist             else if (*setpointOffset == "LowerThresholdNonCritical")
1060b943aaefSJames Feist             {
1061b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "WarningHigh");
1062b943aaefSJames Feist             }
1063b943aaefSJames Feist             else if (*setpointOffset == "LowerThresholdCritical")
1064b943aaefSJames Feist             {
1065b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "CriticalLow");
1066b943aaefSJames Feist             }
1067b943aaefSJames Feist             else if (*setpointOffset == "UpperThresholdCritical")
1068b943aaefSJames Feist             {
1069b9d36b47SEd Tanous                 output.emplace_back("SetPointOffset", "CriticalHigh");
1070b943aaefSJames Feist             }
1071b943aaefSJames Feist             else
1072b943aaefSJames Feist             {
107362598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
10749e9b6049SEd Tanous                 messages::propertyValueNotInList(response->res, name,
1075ace85d60SEd Tanous                                                  "SetPointOffset");
1076b943aaefSJames Feist                 return CreatePIDRet::fail;
1077b943aaefSJames Feist             }
1078b943aaefSJames Feist         }
1079b943aaefSJames Feist 
108083ff9ab6SJames Feist         // doubles
10815f2caaefSJames Feist         for (const auto& pairs : doubles)
108283ff9ab6SJames Feist         {
10835f2caaefSJames Feist             if (!pairs.second)
108483ff9ab6SJames Feist             {
10855f2caaefSJames Feist                 continue;
108683ff9ab6SJames Feist             }
108762598e31SEd Tanous             BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
1088b9d36b47SEd Tanous             output.emplace_back(pairs.first, *pairs.second);
10895f2caaefSJames Feist         }
109083ff9ab6SJames Feist     }
109183ff9ab6SJames Feist 
109283ff9ab6SJames Feist     else if (type == "FanZones")
109383ff9ab6SJames Feist     {
1094b9d36b47SEd Tanous         output.emplace_back("Type", "Pid.Zone");
109583ff9ab6SJames Feist 
10969e9b6049SEd Tanous         std::optional<std::string> chassisId;
10975f2caaefSJames Feist         std::optional<double> failSafePercent;
1098d3ec07f8SJames Feist         std::optional<double> minThermalOutput;
1099afc474aeSMyung Bae         if (!redfish::json_util::readJson( //
1100afc474aeSMyung Bae                 jsonValue, response->res, //
1101afc474aeSMyung Bae                 "Chassis/@odata.id", chassisId, //
1102afc474aeSMyung Bae                 "FailSafePercent", failSafePercent, //
1103afc474aeSMyung Bae                 "MinThermalOutput", minThermalOutput))
110483ff9ab6SJames Feist         {
110583ff9ab6SJames Feist             return CreatePIDRet::fail;
110683ff9ab6SJames Feist         }
11075f2caaefSJames Feist 
11089e9b6049SEd Tanous         if (chassisId)
110983ff9ab6SJames Feist         {
1110717794d5SAppaRao Puli             // /redfish/v1/chassis/chassis_name/
11119e9b6049SEd Tanous             if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
111283ff9ab6SJames Feist             {
11139e9b6049SEd Tanous                 BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
1114ace85d60SEd Tanous                 messages::invalidObject(
1115ef4c65b7SEd Tanous                     response->res,
11169e9b6049SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
111783ff9ab6SJames Feist                 return CreatePIDRet::fail;
111883ff9ab6SJames Feist             }
111983ff9ab6SJames Feist         }
1120d3ec07f8SJames Feist         if (minThermalOutput)
112183ff9ab6SJames Feist         {
1122b9d36b47SEd Tanous             output.emplace_back("MinThermalOutput", *minThermalOutput);
11235f2caaefSJames Feist         }
11245f2caaefSJames Feist         if (failSafePercent)
112583ff9ab6SJames Feist         {
1126b9d36b47SEd Tanous             output.emplace_back("FailSafePercent", *failSafePercent);
11275f2caaefSJames Feist         }
11285f2caaefSJames Feist     }
11295f2caaefSJames Feist     else if (type == "StepwiseControllers")
11305f2caaefSJames Feist     {
1131b9d36b47SEd Tanous         output.emplace_back("Type", "Stepwise");
11325f2caaefSJames Feist 
11339e9b6049SEd Tanous         std::optional<std::vector<nlohmann::json::object_t>> zones;
11349e9b6049SEd Tanous         std::optional<std::vector<nlohmann::json::object_t>> steps;
11355f2caaefSJames Feist         std::optional<std::vector<std::string>> inputs;
11365f2caaefSJames Feist         std::optional<double> positiveHysteresis;
11375f2caaefSJames Feist         std::optional<double> negativeHysteresis;
1138c33a90ecSJames Feist         std::optional<std::string> direction; // upper clipping curve vs lower
1139afc474aeSMyung Bae         if (!redfish::json_util::readJson( //
1140afc474aeSMyung Bae                 jsonValue, response->res, //
1141afc474aeSMyung Bae                 "Direction", direction, //
1142afc474aeSMyung Bae                 "Inputs", inputs, //
1143afc474aeSMyung Bae                 "NegativeHysteresis", negativeHysteresis, //
1144afc474aeSMyung Bae                 "PositiveHysteresis", positiveHysteresis, //
1145afc474aeSMyung Bae                 "Steps", steps, //
1146afc474aeSMyung Bae                 "Zones", zones //
1147afc474aeSMyung Bae                 ))
11485f2caaefSJames Feist         {
114983ff9ab6SJames Feist             return CreatePIDRet::fail;
115083ff9ab6SJames Feist         }
11515f2caaefSJames Feist 
11525f2caaefSJames Feist         if (zones)
115383ff9ab6SJames Feist         {
1154b6baeaa4SJames Feist             std::vector<std::string> zonesStrs;
1155b6baeaa4SJames Feist             if (!getZonesFromJsonReq(response, *zones, zonesStrs))
11565f2caaefSJames Feist             {
115762598e31SEd Tanous                 BMCWEB_LOG_ERROR("Illegal Zones");
115883ff9ab6SJames Feist                 return CreatePIDRet::fail;
115983ff9ab6SJames Feist             }
1160b6baeaa4SJames Feist             if (chassis.empty() &&
1161e662eae8SEd Tanous                 findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
1162b6baeaa4SJames Feist             {
116362598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
1164ace85d60SEd Tanous                 messages::invalidObject(
1165ef4c65b7SEd Tanous                     response->res,
1166ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", chassis));
1167b6baeaa4SJames Feist                 return CreatePIDRet::fail;
1168b6baeaa4SJames Feist             }
1169b9d36b47SEd Tanous             output.emplace_back("Zones", std::move(zonesStrs));
11705f2caaefSJames Feist         }
11715f2caaefSJames Feist         if (steps)
11725f2caaefSJames Feist         {
11735f2caaefSJames Feist             std::vector<double> readings;
11745f2caaefSJames Feist             std::vector<double> outputs;
11755f2caaefSJames Feist             for (auto& step : *steps)
11765f2caaefSJames Feist             {
1177543f4400SEd Tanous                 double target = 0.0;
1178543f4400SEd Tanous                 double out = 0.0;
11795f2caaefSJames Feist 
1180afc474aeSMyung Bae                 if (!redfish::json_util::readJsonObject( //
1181afc474aeSMyung Bae                         step, response->res, //
1182afc474aeSMyung Bae                         "Output", out, //
1183afc474aeSMyung Bae                         "Target", target //
1184afc474aeSMyung Bae                         ))
11855f2caaefSJames Feist                 {
11865f2caaefSJames Feist                     return CreatePIDRet::fail;
11875f2caaefSJames Feist                 }
11885f2caaefSJames Feist                 readings.emplace_back(target);
118923a21a1cSEd Tanous                 outputs.emplace_back(out);
11905f2caaefSJames Feist             }
1191b9d36b47SEd Tanous             output.emplace_back("Reading", std::move(readings));
1192b9d36b47SEd Tanous             output.emplace_back("Output", std::move(outputs));
11935f2caaefSJames Feist         }
11945f2caaefSJames Feist         if (inputs)
11955f2caaefSJames Feist         {
11965f2caaefSJames Feist             for (std::string& value : *inputs)
11975f2caaefSJames Feist             {
1198a170f275SEd Tanous                 std::replace(value.begin(), value.end(), '_', ' ');
11995f2caaefSJames Feist             }
1200b9d36b47SEd Tanous             output.emplace_back("Inputs", std::move(*inputs));
12015f2caaefSJames Feist         }
12025f2caaefSJames Feist         if (negativeHysteresis)
12035f2caaefSJames Feist         {
1204b9d36b47SEd Tanous             output.emplace_back("NegativeHysteresis", *negativeHysteresis);
12055f2caaefSJames Feist         }
12065f2caaefSJames Feist         if (positiveHysteresis)
12075f2caaefSJames Feist         {
1208b9d36b47SEd Tanous             output.emplace_back("PositiveHysteresis", *positiveHysteresis);
120983ff9ab6SJames Feist         }
1210c33a90ecSJames Feist         if (direction)
1211c33a90ecSJames Feist         {
1212c33a90ecSJames Feist             constexpr const std::array<const char*, 2> allowedDirections = {
1213c33a90ecSJames Feist                 "Ceiling", "Floor"};
12143544d2a7SEd Tanous             if (std::ranges::find(allowedDirections, *direction) ==
12153544d2a7SEd Tanous                 allowedDirections.end())
1216c33a90ecSJames Feist             {
1217c33a90ecSJames Feist                 messages::propertyValueTypeError(response->res, "Direction",
1218c33a90ecSJames Feist                                                  *direction);
1219c33a90ecSJames Feist                 return CreatePIDRet::fail;
1220c33a90ecSJames Feist             }
1221b9d36b47SEd Tanous             output.emplace_back("Class", *direction);
1222c33a90ecSJames Feist         }
122383ff9ab6SJames Feist     }
122483ff9ab6SJames Feist     else
122583ff9ab6SJames Feist     {
122662598e31SEd Tanous         BMCWEB_LOG_ERROR("Illegal Type {}", type);
122735a62c7cSJason M. Bills         messages::propertyUnknown(response->res, type);
122883ff9ab6SJames Feist         return CreatePIDRet::fail;
122983ff9ab6SJames Feist     }
123083ff9ab6SJames Feist     return CreatePIDRet::patch;
123183ff9ab6SJames Feist }
123273df0db0SJames Feist struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
123373df0db0SJames Feist {
12346936afe4SEd Tanous     struct CompletionValues
12356936afe4SEd Tanous     {
12366936afe4SEd Tanous         std::vector<std::string> supportedProfiles;
12376936afe4SEd Tanous         std::string currentProfile;
12386936afe4SEd Tanous         dbus::utility::MapperGetSubTreeResponse subtree;
12396936afe4SEd Tanous     };
124083ff9ab6SJames Feist 
12414e23a444SEd Tanous     explicit GetPIDValues(
12424e23a444SEd Tanous         const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
124323a21a1cSEd Tanous         asyncResp(asyncRespIn)
124473df0db0SJames Feist 
12451214b7e7SGunnar Mills     {}
12469c310685SBorawski.Lukasz 
124773df0db0SJames Feist     void run()
12485b4aa86bSJames Feist     {
124973df0db0SJames Feist         std::shared_ptr<GetPIDValues> self = shared_from_this();
125073df0db0SJames Feist 
125173df0db0SJames Feist         // get all configurations
1252e99073f5SGeorge Liu         constexpr std::array<std::string_view, 4> interfaces = {
1253e99073f5SGeorge Liu             pidConfigurationIface, pidZoneConfigurationIface,
1254e99073f5SGeorge Liu             objectManagerIface, stepwiseConfigurationIface};
1255e99073f5SGeorge Liu         dbus::utility::getSubTree(
1256e99073f5SGeorge Liu             "/", 0, interfaces,
1257b9d36b47SEd Tanous             [self](
1258e99073f5SGeorge Liu                 const boost::system::error_code& ec,
1259b9d36b47SEd Tanous                 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
12605b4aa86bSJames Feist                 if (ec)
12615b4aa86bSJames Feist                 {
126262598e31SEd Tanous                     BMCWEB_LOG_ERROR("{}", ec);
126373df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
126473df0db0SJames Feist                     return;
126573df0db0SJames Feist                 }
12666936afe4SEd Tanous                 self->complete.subtree = subtreeLocal;
1267e99073f5SGeorge Liu             });
126873df0db0SJames Feist 
126973df0db0SJames Feist         // at the same time get the selected profile
1270e99073f5SGeorge Liu         constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1271e99073f5SGeorge Liu             thermalModeIface};
1272e99073f5SGeorge Liu         dbus::utility::getSubTree(
1273e99073f5SGeorge Liu             "/", 0, thermalModeIfaces,
1274b9d36b47SEd Tanous             [self](
1275e99073f5SGeorge Liu                 const boost::system::error_code& ec,
1276b9d36b47SEd Tanous                 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
127723a21a1cSEd Tanous                 if (ec || subtreeLocal.empty())
127873df0db0SJames Feist                 {
127973df0db0SJames Feist                     return;
128073df0db0SJames Feist                 }
128123a21a1cSEd Tanous                 if (subtreeLocal[0].second.size() != 1)
128273df0db0SJames Feist                 {
128373df0db0SJames Feist                     // invalid mapper response, should never happen
128462598e31SEd Tanous                     BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
128573df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
12865b4aa86bSJames Feist                     return;
12875b4aa86bSJames Feist                 }
12885b4aa86bSJames Feist 
128923a21a1cSEd Tanous                 const std::string& path = subtreeLocal[0].first;
129023a21a1cSEd Tanous                 const std::string& owner = subtreeLocal[0].second[0].first;
1291fac6e53bSKrzysztof Grobelny 
1292fac6e53bSKrzysztof Grobelny                 sdbusplus::asio::getAllProperties(
1293bd79bce8SPatrick Williams                     *crow::connections::systemBus, owner, path,
1294bd79bce8SPatrick Williams                     thermalModeIface,
1295168e20c1SEd Tanous                     [path, owner,
12965e7e2dc5SEd Tanous                      self](const boost::system::error_code& ec2,
1297b9d36b47SEd Tanous                            const dbus::utility::DBusPropertiesMap& resp) {
129823a21a1cSEd Tanous                         if (ec2)
129973df0db0SJames Feist                         {
130062598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1301bd79bce8SPatrick Williams                                 "GetPIDValues: Can't get thermalModeIface {}",
1302bd79bce8SPatrick Williams                                 path);
130373df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
130473df0db0SJames Feist                             return;
130573df0db0SJames Feist                         }
1306fac6e53bSKrzysztof Grobelny 
1307271584abSEd Tanous                         const std::string* current = nullptr;
1308271584abSEd Tanous                         const std::vector<std::string>* supported = nullptr;
1309fac6e53bSKrzysztof Grobelny 
1310fac6e53bSKrzysztof Grobelny                         const bool success = sdbusplus::unpackPropertiesNoThrow(
1311bd79bce8SPatrick Williams                             dbus_utils::UnpackErrorPrinter(), resp, "Current",
1312bd79bce8SPatrick Williams                             current, "Supported", supported);
1313fac6e53bSKrzysztof Grobelny 
1314fac6e53bSKrzysztof Grobelny                         if (!success)
131573df0db0SJames Feist                         {
1316002d39b4SEd Tanous                             messages::internalError(self->asyncResp->res);
131773df0db0SJames Feist                             return;
131873df0db0SJames Feist                         }
1319fac6e53bSKrzysztof Grobelny 
132073df0db0SJames Feist                         if (current == nullptr || supported == nullptr)
132173df0db0SJames Feist                         {
132262598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1323bd79bce8SPatrick Williams                                 "GetPIDValues: thermal mode iface invalid {}",
1324bd79bce8SPatrick Williams                                 path);
132573df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
132673df0db0SJames Feist                             return;
132773df0db0SJames Feist                         }
13286936afe4SEd Tanous                         self->complete.currentProfile = *current;
13296936afe4SEd Tanous                         self->complete.supportedProfiles = *supported;
1330fac6e53bSKrzysztof Grobelny                     });
1331e99073f5SGeorge Liu             });
133273df0db0SJames Feist     }
133373df0db0SJames Feist 
13346936afe4SEd Tanous     static void
13356936afe4SEd Tanous         processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
13366936afe4SEd Tanous                            const CompletionValues& completion)
133773df0db0SJames Feist     {
133873df0db0SJames Feist         if (asyncResp->res.result() != boost::beast::http::status::ok)
133973df0db0SJames Feist         {
134073df0db0SJames Feist             return;
134173df0db0SJames Feist         }
13425b4aa86bSJames Feist         // create map of <connection, path to objMgr>>
13436936afe4SEd Tanous         boost::container::flat_map<
13446936afe4SEd Tanous             std::string, std::string, std::less<>,
13456936afe4SEd Tanous             std::vector<std::pair<std::string, std::string>>>
13466936afe4SEd Tanous             objectMgrPaths;
13476936afe4SEd Tanous         boost::container::flat_set<std::string, std::less<>,
13486936afe4SEd Tanous                                    std::vector<std::string>>
13496936afe4SEd Tanous             calledConnections;
13506936afe4SEd Tanous         for (const auto& pathGroup : completion.subtree)
13515b4aa86bSJames Feist         {
13525b4aa86bSJames Feist             for (const auto& connectionGroup : pathGroup.second)
13535b4aa86bSJames Feist             {
13546bce33bcSJames Feist                 auto findConnection =
13556bce33bcSJames Feist                     calledConnections.find(connectionGroup.first);
13566bce33bcSJames Feist                 if (findConnection != calledConnections.end())
13576bce33bcSJames Feist                 {
13586bce33bcSJames Feist                     break;
13596bce33bcSJames Feist                 }
136073df0db0SJames Feist                 for (const std::string& interface : connectionGroup.second)
13615b4aa86bSJames Feist                 {
13625b4aa86bSJames Feist                     if (interface == objectManagerIface)
13635b4aa86bSJames Feist                     {
136473df0db0SJames Feist                         objectMgrPaths[connectionGroup.first] = pathGroup.first;
13655b4aa86bSJames Feist                     }
13665b4aa86bSJames Feist                     // this list is alphabetical, so we
13675b4aa86bSJames Feist                     // should have found the objMgr by now
13685b4aa86bSJames Feist                     if (interface == pidConfigurationIface ||
1369b7a08d04SJames Feist                         interface == pidZoneConfigurationIface ||
1370b7a08d04SJames Feist                         interface == stepwiseConfigurationIface)
13715b4aa86bSJames Feist                     {
13725b4aa86bSJames Feist                         auto findObjMgr =
13735b4aa86bSJames Feist                             objectMgrPaths.find(connectionGroup.first);
13745b4aa86bSJames Feist                         if (findObjMgr == objectMgrPaths.end())
13755b4aa86bSJames Feist                         {
137662598e31SEd Tanous                             BMCWEB_LOG_DEBUG("{}Has no Object Manager",
137762598e31SEd Tanous                                              connectionGroup.first);
13785b4aa86bSJames Feist                             continue;
13795b4aa86bSJames Feist                         }
13806bce33bcSJames Feist 
13816bce33bcSJames Feist                         calledConnections.insert(connectionGroup.first);
13826bce33bcSJames Feist 
138373df0db0SJames Feist                         asyncPopulatePid(findObjMgr->first, findObjMgr->second,
13846936afe4SEd Tanous                                          completion.currentProfile,
13856936afe4SEd Tanous                                          completion.supportedProfiles,
138673df0db0SJames Feist                                          asyncResp);
13875b4aa86bSJames Feist                         break;
13885b4aa86bSJames Feist                     }
13895b4aa86bSJames Feist                 }
13905b4aa86bSJames Feist             }
13915b4aa86bSJames Feist         }
139273df0db0SJames Feist     }
139373df0db0SJames Feist 
13946936afe4SEd Tanous     ~GetPIDValues()
13956936afe4SEd Tanous     {
13966936afe4SEd Tanous         boost::asio::post(crow::connections::systemBus->get_io_context(),
13976936afe4SEd Tanous                           std::bind_front(&processingComplete, asyncResp,
13986936afe4SEd Tanous                                           std::move(complete)));
13996936afe4SEd Tanous     }
14006936afe4SEd Tanous 
1401ecd6a3a2SEd Tanous     GetPIDValues(const GetPIDValues&) = delete;
1402ecd6a3a2SEd Tanous     GetPIDValues(GetPIDValues&&) = delete;
1403ecd6a3a2SEd Tanous     GetPIDValues& operator=(const GetPIDValues&) = delete;
1404ecd6a3a2SEd Tanous     GetPIDValues& operator=(GetPIDValues&&) = delete;
1405ecd6a3a2SEd Tanous 
14068d1b46d7Szhanghch05     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
14076936afe4SEd Tanous     CompletionValues complete;
140873df0db0SJames Feist };
140973df0db0SJames Feist 
141073df0db0SJames Feist struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
141173df0db0SJames Feist {
14129e9b6049SEd Tanous     SetPIDValues(
14139e9b6049SEd Tanous         const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
14149e9b6049SEd Tanous         std::vector<
14159e9b6049SEd Tanous             std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
14169e9b6049SEd Tanous             configurationsIn,
14179e9b6049SEd Tanous         std::optional<std::string>& profileIn) :
1418bd79bce8SPatrick Williams         asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
14199e9b6049SEd Tanous         profile(std::move(profileIn))
14209e9b6049SEd Tanous     {}
1421ecd6a3a2SEd Tanous 
1422ecd6a3a2SEd Tanous     SetPIDValues(const SetPIDValues&) = delete;
1423ecd6a3a2SEd Tanous     SetPIDValues(SetPIDValues&&) = delete;
1424ecd6a3a2SEd Tanous     SetPIDValues& operator=(const SetPIDValues&) = delete;
1425ecd6a3a2SEd Tanous     SetPIDValues& operator=(SetPIDValues&&) = delete;
1426ecd6a3a2SEd Tanous 
142773df0db0SJames Feist     void run()
142873df0db0SJames Feist     {
142973df0db0SJames Feist         if (asyncResp->res.result() != boost::beast::http::status::ok)
143073df0db0SJames Feist         {
143173df0db0SJames Feist             return;
143273df0db0SJames Feist         }
143373df0db0SJames Feist 
143473df0db0SJames Feist         std::shared_ptr<SetPIDValues> self = shared_from_this();
143573df0db0SJames Feist 
143673df0db0SJames Feist         // todo(james): might make sense to do a mapper call here if this
143773df0db0SJames Feist         // interface gets more traction
14385eb468daSGeorge Liu         sdbusplus::message::object_path objPath(
14395eb468daSGeorge Liu             "/xyz/openbmc_project/inventory");
14405eb468daSGeorge Liu         dbus::utility::getManagedObjects(
14415eb468daSGeorge Liu             "xyz.openbmc_project.EntityManager", objPath,
14425e7e2dc5SEd Tanous             [self](const boost::system::error_code& ec,
1443914e2d5dSEd Tanous                    const dbus::utility::ManagedObjectType& mObj) {
144473df0db0SJames Feist                 if (ec)
144573df0db0SJames Feist                 {
144662598e31SEd Tanous                     BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
144773df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
144873df0db0SJames Feist                     return;
144973df0db0SJames Feist                 }
1450e69d9de2SJames Feist                 const std::array<const char*, 3> configurations = {
1451e69d9de2SJames Feist                     pidConfigurationIface, pidZoneConfigurationIface,
1452e69d9de2SJames Feist                     stepwiseConfigurationIface};
1453e69d9de2SJames Feist 
145414b0b8d5SJames Feist                 for (const auto& [path, object] : mObj)
1455e69d9de2SJames Feist                 {
145614b0b8d5SJames Feist                     for (const auto& [interface, _] : object)
1457e69d9de2SJames Feist                     {
14583544d2a7SEd Tanous                         if (std::ranges::find(configurations, interface) !=
14593544d2a7SEd Tanous                             configurations.end())
1460e69d9de2SJames Feist                         {
146114b0b8d5SJames Feist                             self->objectCount++;
1462e69d9de2SJames Feist                             break;
1463e69d9de2SJames Feist                         }
1464e69d9de2SJames Feist                     }
1465e69d9de2SJames Feist                 }
1466914e2d5dSEd Tanous                 self->managedObj = mObj;
14675eb468daSGeorge Liu             });
146873df0db0SJames Feist 
146973df0db0SJames Feist         // at the same time get the profile information
1470e99073f5SGeorge Liu         constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1471e99073f5SGeorge Liu             thermalModeIface};
1472e99073f5SGeorge Liu         dbus::utility::getSubTree(
1473e99073f5SGeorge Liu             "/", 0, thermalModeIfaces,
1474e99073f5SGeorge Liu             [self](const boost::system::error_code& ec,
1475b9d36b47SEd Tanous                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
147673df0db0SJames Feist                 if (ec || subtree.empty())
147773df0db0SJames Feist                 {
147873df0db0SJames Feist                     return;
147973df0db0SJames Feist                 }
148073df0db0SJames Feist                 if (subtree[0].second.empty())
148173df0db0SJames Feist                 {
148273df0db0SJames Feist                     // invalid mapper response, should never happen
148362598e31SEd Tanous                     BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
148473df0db0SJames Feist                     messages::internalError(self->asyncResp->res);
148573df0db0SJames Feist                     return;
148673df0db0SJames Feist                 }
148773df0db0SJames Feist 
148873df0db0SJames Feist                 const std::string& path = subtree[0].first;
148973df0db0SJames Feist                 const std::string& owner = subtree[0].second[0].first;
1490fac6e53bSKrzysztof Grobelny                 sdbusplus::asio::getAllProperties(
1491bd79bce8SPatrick Williams                     *crow::connections::systemBus, owner, path,
1492bd79bce8SPatrick Williams                     thermalModeIface,
1493bd79bce8SPatrick Williams                     [self, path,
1494bd79bce8SPatrick Williams                      owner](const boost::system::error_code& ec2,
1495b9d36b47SEd Tanous                             const dbus::utility::DBusPropertiesMap& r) {
1496cb13a392SEd Tanous                         if (ec2)
149773df0db0SJames Feist                         {
149862598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1499bd79bce8SPatrick Williams                                 "SetPIDValues: Can't get thermalModeIface {}",
1500bd79bce8SPatrick Williams                                 path);
150173df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
150273df0db0SJames Feist                             return;
150373df0db0SJames Feist                         }
1504271584abSEd Tanous                         const std::string* current = nullptr;
1505271584abSEd Tanous                         const std::vector<std::string>* supported = nullptr;
1506fac6e53bSKrzysztof Grobelny 
1507fac6e53bSKrzysztof Grobelny                         const bool success = sdbusplus::unpackPropertiesNoThrow(
1508bd79bce8SPatrick Williams                             dbus_utils::UnpackErrorPrinter(), r, "Current",
1509bd79bce8SPatrick Williams                             current, "Supported", supported);
1510fac6e53bSKrzysztof Grobelny 
1511fac6e53bSKrzysztof Grobelny                         if (!success)
151273df0db0SJames Feist                         {
1513002d39b4SEd Tanous                             messages::internalError(self->asyncResp->res);
151473df0db0SJames Feist                             return;
151573df0db0SJames Feist                         }
1516fac6e53bSKrzysztof Grobelny 
151773df0db0SJames Feist                         if (current == nullptr || supported == nullptr)
151873df0db0SJames Feist                         {
151962598e31SEd Tanous                             BMCWEB_LOG_ERROR(
1520bd79bce8SPatrick Williams                                 "SetPIDValues: thermal mode iface invalid {}",
1521bd79bce8SPatrick Williams                                 path);
152273df0db0SJames Feist                             messages::internalError(self->asyncResp->res);
152373df0db0SJames Feist                             return;
152473df0db0SJames Feist                         }
152573df0db0SJames Feist                         self->currentProfile = *current;
152673df0db0SJames Feist                         self->supportedProfiles = *supported;
152773df0db0SJames Feist                         self->profileConnection = owner;
152873df0db0SJames Feist                         self->profilePath = path;
1529fac6e53bSKrzysztof Grobelny                     });
1530e99073f5SGeorge Liu             });
153173df0db0SJames Feist     }
153224b2fe81SEd Tanous     void pidSetDone()
153373df0db0SJames Feist     {
153473df0db0SJames Feist         if (asyncResp->res.result() != boost::beast::http::status::ok)
153573df0db0SJames Feist         {
153673df0db0SJames Feist             return;
15375b4aa86bSJames Feist         }
15388d1b46d7Szhanghch05         std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
153973df0db0SJames Feist         if (profile)
154073df0db0SJames Feist         {
15413544d2a7SEd Tanous             if (std::ranges::find(supportedProfiles, *profile) ==
15423544d2a7SEd Tanous                 supportedProfiles.end())
154373df0db0SJames Feist             {
154473df0db0SJames Feist                 messages::actionParameterUnknown(response->res, "Profile",
154573df0db0SJames Feist                                                  *profile);
154673df0db0SJames Feist                 return;
154773df0db0SJames Feist             }
154873df0db0SJames Feist             currentProfile = *profile;
15499ae226faSGeorge Liu             sdbusplus::asio::setProperty(
15509ae226faSGeorge Liu                 *crow::connections::systemBus, profileConnection, profilePath,
15519ae226faSGeorge Liu                 thermalModeIface, "Current", *profile,
15525e7e2dc5SEd Tanous                 [response](const boost::system::error_code& ec) {
155373df0db0SJames Feist                     if (ec)
155473df0db0SJames Feist                     {
155562598e31SEd Tanous                         BMCWEB_LOG_ERROR("Error patching profile{}", ec);
155673df0db0SJames Feist                         messages::internalError(response->res);
155773df0db0SJames Feist                     }
15589ae226faSGeorge Liu                 });
155973df0db0SJames Feist         }
156073df0db0SJames Feist 
156173df0db0SJames Feist         for (auto& containerPair : configuration)
156273df0db0SJames Feist         {
156373df0db0SJames Feist             auto& container = containerPair.second;
156473df0db0SJames Feist             if (!container)
156573df0db0SJames Feist             {
156673df0db0SJames Feist                 continue;
156773df0db0SJames Feist             }
15686ee7f774SJames Feist 
156902cad96eSEd Tanous             const std::string& type = containerPair.first;
157073df0db0SJames Feist 
15719e9b6049SEd Tanous             for (auto& [name, value] : *container)
157273df0db0SJames Feist             {
1573cddbf3dfSPotin Lai                 std::string dbusObjName = name;
1574cddbf3dfSPotin Lai                 std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
157562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("looking for {}", name);
15766ee7f774SJames Feist 
15773544d2a7SEd Tanous                 auto pathItr = std::ranges::find_if(
15783544d2a7SEd Tanous                     managedObj, [&dbusObjName](const auto& obj) {
157991f75cafSEd Tanous                         return obj.first.filename() == dbusObjName;
158073df0db0SJames Feist                     });
1581b9d36b47SEd Tanous                 dbus::utility::DBusPropertiesMap output;
158273df0db0SJames Feist 
158373df0db0SJames Feist                 output.reserve(16); // The pid interface length
158473df0db0SJames Feist 
158573df0db0SJames Feist                 // determines if we're patching entity-manager or
158673df0db0SJames Feist                 // creating a new object
158773df0db0SJames Feist                 bool createNewObject = (pathItr == managedObj.end());
158862598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
15896ee7f774SJames Feist 
159073df0db0SJames Feist                 std::string iface;
1591ea2b670dSEd Tanous                 if (!createNewObject)
1592ea2b670dSEd Tanous                 {
15938be2b5b6SPotin Lai                     bool findInterface = false;
1594ea2b670dSEd Tanous                     for (const auto& interface : pathItr->second)
1595ea2b670dSEd Tanous                     {
1596ea2b670dSEd Tanous                         if (interface.first == pidConfigurationIface)
1597ea2b670dSEd Tanous                         {
1598ea2b670dSEd Tanous                             if (type == "PidControllers" ||
1599ea2b670dSEd Tanous                                 type == "FanControllers")
160073df0db0SJames Feist                             {
160173df0db0SJames Feist                                 iface = pidConfigurationIface;
16028be2b5b6SPotin Lai                                 findInterface = true;
16038be2b5b6SPotin Lai                                 break;
160473df0db0SJames Feist                             }
160573df0db0SJames Feist                         }
1606ea2b670dSEd Tanous                         else if (interface.first == pidZoneConfigurationIface)
160773df0db0SJames Feist                         {
1608ea2b670dSEd Tanous                             if (type == "FanZones")
160973df0db0SJames Feist                             {
1610da39350aSPavanKumarIntel                                 iface = pidZoneConfigurationIface;
16118be2b5b6SPotin Lai                                 findInterface = true;
16128be2b5b6SPotin Lai                                 break;
161373df0db0SJames Feist                             }
161473df0db0SJames Feist                         }
1615ea2b670dSEd Tanous                         else if (interface.first == stepwiseConfigurationIface)
1616ea2b670dSEd Tanous                         {
1617ea2b670dSEd Tanous                             if (type == "StepwiseControllers")
161873df0db0SJames Feist                             {
161973df0db0SJames Feist                                 iface = stepwiseConfigurationIface;
16208be2b5b6SPotin Lai                                 findInterface = true;
16218be2b5b6SPotin Lai                                 break;
16228be2b5b6SPotin Lai                             }
16238be2b5b6SPotin Lai                         }
16248be2b5b6SPotin Lai                     }
16258be2b5b6SPotin Lai 
16268be2b5b6SPotin Lai                     // create new object if interface not found
16278be2b5b6SPotin Lai                     if (!findInterface)
16288be2b5b6SPotin Lai                     {
162973df0db0SJames Feist                         createNewObject = true;
163073df0db0SJames Feist                     }
1631ea2b670dSEd Tanous                 }
16326ee7f774SJames Feist 
16339e9b6049SEd Tanous                 if (createNewObject && value == nullptr)
16346ee7f774SJames Feist                 {
16354e0453b1SGunnar Mills                     // can't delete a non-existent object
16369e9b6049SEd Tanous                     messages::propertyValueNotInList(response->res, value,
1637e2616cc5SEd Tanous                                                      name);
16386ee7f774SJames Feist                     continue;
16396ee7f774SJames Feist                 }
16406ee7f774SJames Feist 
16416ee7f774SJames Feist                 std::string path;
16426ee7f774SJames Feist                 if (pathItr != managedObj.end())
16436ee7f774SJames Feist                 {
16446ee7f774SJames Feist                     path = pathItr->first.str;
16456ee7f774SJames Feist                 }
16466ee7f774SJames Feist 
164762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
1648e69d9de2SJames Feist 
1649e69d9de2SJames Feist                 // arbitrary limit to avoid attacks
1650e69d9de2SJames Feist                 constexpr const size_t controllerLimit = 500;
165114b0b8d5SJames Feist                 if (createNewObject && objectCount >= controllerLimit)
1652e69d9de2SJames Feist                 {
1653e69d9de2SJames Feist                     messages::resourceExhaustion(response->res, type);
1654e69d9de2SJames Feist                     continue;
1655e69d9de2SJames Feist                 }
1656a170f275SEd Tanous                 std::string escaped = name;
1657a170f275SEd Tanous                 std::replace(escaped.begin(), escaped.end(), '_', ' ');
1658a170f275SEd Tanous                 output.emplace_back("Name", escaped);
165973df0db0SJames Feist 
166073df0db0SJames Feist                 std::string chassis;
166173df0db0SJames Feist                 CreatePIDRet ret = createPidInterface(
16629e9b6049SEd Tanous                     response, type, name, value, path, managedObj,
16639e9b6049SEd Tanous                     createNewObject, output, chassis, currentProfile);
166473df0db0SJames Feist                 if (ret == CreatePIDRet::fail)
166573df0db0SJames Feist                 {
166673df0db0SJames Feist                     return;
166773df0db0SJames Feist                 }
16683174e4dfSEd Tanous                 if (ret == CreatePIDRet::del)
166973df0db0SJames Feist                 {
167073df0db0SJames Feist                     continue;
167173df0db0SJames Feist                 }
167273df0db0SJames Feist 
167373df0db0SJames Feist                 if (!createNewObject)
167473df0db0SJames Feist                 {
167573df0db0SJames Feist                     for (const auto& property : output)
167673df0db0SJames Feist                     {
16777a696974SPotin Lai                         crow::connections::systemBus->async_method_call(
167873df0db0SJames Feist                             [response,
167973df0db0SJames Feist                              propertyName{std::string(property.first)}](
16805e7e2dc5SEd Tanous                                 const boost::system::error_code& ec) {
168173df0db0SJames Feist                                 if (ec)
168273df0db0SJames Feist                                 {
168362598e31SEd Tanous                                     BMCWEB_LOG_ERROR("Error patching {}: {}",
168462598e31SEd Tanous                                                      propertyName, ec);
168573df0db0SJames Feist                                     messages::internalError(response->res);
168673df0db0SJames Feist                                     return;
168773df0db0SJames Feist                                 }
168873df0db0SJames Feist                                 messages::success(response->res);
16897a696974SPotin Lai                             },
16907a696974SPotin Lai                             "xyz.openbmc_project.EntityManager", path,
16917a696974SPotin Lai                             "org.freedesktop.DBus.Properties", "Set", iface,
16927a696974SPotin Lai                             property.first, property.second);
169373df0db0SJames Feist                     }
169473df0db0SJames Feist                 }
169573df0db0SJames Feist                 else
169673df0db0SJames Feist                 {
169773df0db0SJames Feist                     if (chassis.empty())
169873df0db0SJames Feist                     {
169962598e31SEd Tanous                         BMCWEB_LOG_ERROR("Failed to get chassis from config");
1700ace85d60SEd Tanous                         messages::internalError(response->res);
170173df0db0SJames Feist                         return;
170273df0db0SJames Feist                     }
170373df0db0SJames Feist 
170473df0db0SJames Feist                     bool foundChassis = false;
170573df0db0SJames Feist                     for (const auto& obj : managedObj)
170673df0db0SJames Feist                     {
170791f75cafSEd Tanous                         if (obj.first.filename() == chassis)
170873df0db0SJames Feist                         {
170973df0db0SJames Feist                             chassis = obj.first.str;
171073df0db0SJames Feist                             foundChassis = true;
171173df0db0SJames Feist                             break;
171273df0db0SJames Feist                         }
171373df0db0SJames Feist                     }
171473df0db0SJames Feist                     if (!foundChassis)
171573df0db0SJames Feist                     {
171662598e31SEd Tanous                         BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
171773df0db0SJames Feist                         messages::resourceMissingAtURI(
1718ace85d60SEd Tanous                             response->res,
1719ef4c65b7SEd Tanous                             boost::urls::format("/redfish/v1/Chassis/{}",
1720ef4c65b7SEd Tanous                                                 chassis));
172173df0db0SJames Feist                         return;
172273df0db0SJames Feist                     }
172373df0db0SJames Feist 
172473df0db0SJames Feist                     crow::connections::systemBus->async_method_call(
17255e7e2dc5SEd Tanous                         [response](const boost::system::error_code& ec) {
172673df0db0SJames Feist                             if (ec)
172773df0db0SJames Feist                             {
1728bd79bce8SPatrick Williams                                 BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
1729bd79bce8SPatrick Williams                                                  ec);
173073df0db0SJames Feist                                 messages::internalError(response->res);
173173df0db0SJames Feist                                 return;
173273df0db0SJames Feist                             }
173373df0db0SJames Feist                             messages::success(response->res);
173473df0db0SJames Feist                         },
173573df0db0SJames Feist                         "xyz.openbmc_project.EntityManager", chassis,
173673df0db0SJames Feist                         "xyz.openbmc_project.AddObject", "AddObject", output);
173773df0db0SJames Feist                 }
173873df0db0SJames Feist             }
173973df0db0SJames Feist         }
174073df0db0SJames Feist     }
174124b2fe81SEd Tanous 
174224b2fe81SEd Tanous     ~SetPIDValues()
174324b2fe81SEd Tanous     {
174424b2fe81SEd Tanous         try
174524b2fe81SEd Tanous         {
174624b2fe81SEd Tanous             pidSetDone();
174724b2fe81SEd Tanous         }
174824b2fe81SEd Tanous         catch (...)
174924b2fe81SEd Tanous         {
175062598e31SEd Tanous             BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
175124b2fe81SEd Tanous         }
175224b2fe81SEd Tanous     }
175324b2fe81SEd Tanous 
17548d1b46d7Szhanghch05     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
17559e9b6049SEd Tanous     std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
175673df0db0SJames Feist         configuration;
175773df0db0SJames Feist     std::optional<std::string> profile;
175873df0db0SJames Feist     dbus::utility::ManagedObjectType managedObj;
175973df0db0SJames Feist     std::vector<std::string> supportedProfiles;
176073df0db0SJames Feist     std::string currentProfile;
176173df0db0SJames Feist     std::string profileConnection;
176273df0db0SJames Feist     std::string profilePath;
176314b0b8d5SJames Feist     size_t objectCount = 0;
176473df0db0SJames Feist };
176573df0db0SJames Feist 
1766071d8fdfSSunnySrivastava1984 /**
1767071d8fdfSSunnySrivastava1984  * @brief Retrieves BMC manager location data over DBus
1768071d8fdfSSunnySrivastava1984  *
1769ac106bf6SEd Tanous  * @param[in] asyncResp Shared pointer for completing asynchronous calls
1770071d8fdfSSunnySrivastava1984  * @param[in] connectionName - service name
1771071d8fdfSSunnySrivastava1984  * @param[in] path - object path
1772071d8fdfSSunnySrivastava1984  * @return none
1773071d8fdfSSunnySrivastava1984  */
1774ac106bf6SEd Tanous inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1775071d8fdfSSunnySrivastava1984                         const std::string& connectionName,
1776071d8fdfSSunnySrivastava1984                         const std::string& path)
1777071d8fdfSSunnySrivastava1984 {
177862598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get BMC manager Location data.");
1779071d8fdfSSunnySrivastava1984 
17801e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
17811e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
17821e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
1783ac106bf6SEd Tanous         [asyncResp](const boost::system::error_code& ec,
17841e1e598dSJonathan Doman                     const std::string& property) {
1785071d8fdfSSunnySrivastava1984             if (ec)
1786071d8fdfSSunnySrivastava1984             {
178762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error for "
178862598e31SEd Tanous                                  "Location");
1789ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
1790071d8fdfSSunnySrivastava1984                 return;
1791071d8fdfSSunnySrivastava1984             }
1792071d8fdfSSunnySrivastava1984 
1793bd79bce8SPatrick Williams             asyncResp->res
1794bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
17951e1e598dSJonathan Doman                 property;
17961e1e598dSJonathan Doman         });
1797071d8fdfSSunnySrivastava1984 }
17987e860f15SJohn Edward Broadbent // avoid name collision systems.hpp
17997e860f15SJohn Edward Broadbent inline void
1800ac106bf6SEd Tanous     managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
18014bf2b033SGunnar Mills {
180262598e31SEd Tanous     BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time");
18034bf2b033SGunnar Mills 
18041e1e598dSJonathan Doman     sdbusplus::asio::getProperty<uint64_t>(
18051e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.BMC",
18061e1e598dSJonathan Doman         "/xyz/openbmc_project/state/bmc0", "xyz.openbmc_project.State.BMC",
18071e1e598dSJonathan Doman         "LastRebootTime",
1808ac106bf6SEd Tanous         [asyncResp](const boost::system::error_code& ec,
18091e1e598dSJonathan Doman                     const uint64_t lastResetTime) {
18104bf2b033SGunnar Mills             if (ec)
18114bf2b033SGunnar Mills             {
181262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
18134bf2b033SGunnar Mills                 return;
18144bf2b033SGunnar Mills             }
18154bf2b033SGunnar Mills 
18164bf2b033SGunnar Mills             // LastRebootTime is epoch time, in milliseconds
18174bf2b033SGunnar Mills             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
18181e1e598dSJonathan Doman             uint64_t lastResetTimeStamp = lastResetTime / 1000;
18194bf2b033SGunnar Mills 
18204bf2b033SGunnar Mills             // Convert to ISO 8601 standard
1821ac106bf6SEd Tanous             asyncResp->res.jsonValue["LastResetTime"] =
18222b82937eSEd Tanous                 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
18231e1e598dSJonathan Doman         });
18244bf2b033SGunnar Mills }
18254bf2b033SGunnar Mills 
18264bfefa74SGunnar Mills /**
18274bfefa74SGunnar Mills  * @brief Set the running firmware image
18284bfefa74SGunnar Mills  *
1829ac106bf6SEd Tanous  * @param[i,o] asyncResp - Async response object
18304bfefa74SGunnar Mills  * @param[i] runningFirmwareTarget - Image to make the running image
18314bfefa74SGunnar Mills  *
18324bfefa74SGunnar Mills  * @return void
18334bfefa74SGunnar Mills  */
18347e860f15SJohn Edward Broadbent inline void
1835ac106bf6SEd Tanous     setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1836f23b7296SEd Tanous                            const std::string& runningFirmwareTarget)
18374bfefa74SGunnar Mills {
18384bfefa74SGunnar Mills     // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1839f23b7296SEd Tanous     std::string::size_type idPos = runningFirmwareTarget.rfind('/');
18404bfefa74SGunnar Mills     if (idPos == std::string::npos)
18414bfefa74SGunnar Mills     {
1842ac106bf6SEd Tanous         messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
18434bfefa74SGunnar Mills                                          "@odata.id");
184462598e31SEd Tanous         BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
18454bfefa74SGunnar Mills         return;
18464bfefa74SGunnar Mills     }
18474bfefa74SGunnar Mills     idPos++;
18484bfefa74SGunnar Mills     if (idPos >= runningFirmwareTarget.size())
18494bfefa74SGunnar Mills     {
1850ac106bf6SEd Tanous         messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
18514bfefa74SGunnar Mills                                          "@odata.id");
185262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid firmware ID.");
18534bfefa74SGunnar Mills         return;
18544bfefa74SGunnar Mills     }
18554bfefa74SGunnar Mills     std::string firmwareId = runningFirmwareTarget.substr(idPos);
18564bfefa74SGunnar Mills 
18574bfefa74SGunnar Mills     // Make sure the image is valid before setting priority
18585eb468daSGeorge Liu     sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
18595eb468daSGeorge Liu     dbus::utility::getManagedObjects(
1860*d27c31e9SJagpal Singh Gill         getBMCUpdateServiceName(), objPath,
18615eb468daSGeorge Liu         [asyncResp, firmwareId, runningFirmwareTarget](
18625eb468daSGeorge Liu             const boost::system::error_code& ec,
18635eb468daSGeorge Liu             const dbus::utility::ManagedObjectType& subtree) {
18644bfefa74SGunnar Mills             if (ec)
18654bfefa74SGunnar Mills             {
186662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
1867ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
18684bfefa74SGunnar Mills                 return;
18694bfefa74SGunnar Mills             }
18704bfefa74SGunnar Mills 
187126f6976fSEd Tanous             if (subtree.empty())
18724bfefa74SGunnar Mills             {
187362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't find image!");
1874ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
18754bfefa74SGunnar Mills                 return;
18764bfefa74SGunnar Mills             }
18774bfefa74SGunnar Mills 
18784bfefa74SGunnar Mills             bool foundImage = false;
187902cad96eSEd Tanous             for (const auto& object : subtree)
18804bfefa74SGunnar Mills             {
18814bfefa74SGunnar Mills                 const std::string& path =
18824bfefa74SGunnar Mills                     static_cast<const std::string&>(object.first);
1883f23b7296SEd Tanous                 std::size_t idPos2 = path.rfind('/');
18844bfefa74SGunnar Mills 
18854bfefa74SGunnar Mills                 if (idPos2 == std::string::npos)
18864bfefa74SGunnar Mills                 {
18874bfefa74SGunnar Mills                     continue;
18884bfefa74SGunnar Mills                 }
18894bfefa74SGunnar Mills 
18904bfefa74SGunnar Mills                 idPos2++;
18914bfefa74SGunnar Mills                 if (idPos2 >= path.size())
18924bfefa74SGunnar Mills                 {
18934bfefa74SGunnar Mills                     continue;
18944bfefa74SGunnar Mills                 }
18954bfefa74SGunnar Mills 
18964bfefa74SGunnar Mills                 if (path.substr(idPos2) == firmwareId)
18974bfefa74SGunnar Mills                 {
18984bfefa74SGunnar Mills                     foundImage = true;
18994bfefa74SGunnar Mills                     break;
19004bfefa74SGunnar Mills                 }
19014bfefa74SGunnar Mills             }
19024bfefa74SGunnar Mills 
19034bfefa74SGunnar Mills             if (!foundImage)
19044bfefa74SGunnar Mills             {
1905ac106bf6SEd Tanous                 messages::propertyValueNotInList(
1906ac106bf6SEd Tanous                     asyncResp->res, runningFirmwareTarget, "@odata.id");
190762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
19084bfefa74SGunnar Mills                 return;
19094bfefa74SGunnar Mills             }
19104bfefa74SGunnar Mills 
191162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
191262598e31SEd Tanous                              firmwareId);
19134bfefa74SGunnar Mills 
19144bfefa74SGunnar Mills             // Only support Immediate
19154bfefa74SGunnar Mills             // An addition could be a Redfish Setting like
19164bfefa74SGunnar Mills             // ActiveSoftwareImageApplyTime and support OnReset
19179ae226faSGeorge Liu             sdbusplus::asio::setProperty(
1918*d27c31e9SJagpal Singh Gill                 *crow::connections::systemBus, getBMCUpdateServiceName(),
19199ae226faSGeorge Liu                 "/xyz/openbmc_project/software/" + firmwareId,
19209ae226faSGeorge Liu                 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
19219ae226faSGeorge Liu                 static_cast<uint8_t>(0),
1922ac106bf6SEd Tanous                 [asyncResp](const boost::system::error_code& ec2) {
19238a592810SEd Tanous                     if (ec2)
19244bfefa74SGunnar Mills                     {
192562598e31SEd Tanous                         BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1926ac106bf6SEd Tanous                         messages::internalError(asyncResp->res);
19274bfefa74SGunnar Mills                         return;
19284bfefa74SGunnar Mills                     }
1929ac106bf6SEd Tanous                     doBMCGracefulRestart(asyncResp);
19309ae226faSGeorge Liu                 });
19315eb468daSGeorge Liu         });
19324bfefa74SGunnar Mills }
19334bfefa74SGunnar Mills 
1934bd79bce8SPatrick Williams inline void afterSetDateTime(
1935bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1936bd79bce8SPatrick Williams     const boost::system::error_code& ec, const sdbusplus::message_t& msg)
1937c51afd54SEd Tanous {
1938c51afd54SEd Tanous     if (ec)
1939c51afd54SEd Tanous     {
1940c51afd54SEd Tanous         BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1941c51afd54SEd Tanous                          ec);
1942c51afd54SEd Tanous         const sd_bus_error* dbusError = msg.get_error();
1943c51afd54SEd Tanous         if (dbusError != nullptr)
1944c51afd54SEd Tanous         {
1945c51afd54SEd Tanous             std::string_view errorName(dbusError->name);
1946c51afd54SEd Tanous             if (errorName ==
1947c51afd54SEd Tanous                 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1948c51afd54SEd Tanous             {
1949c51afd54SEd Tanous                 BMCWEB_LOG_DEBUG("Setting conflict");
1950c51afd54SEd Tanous                 messages::propertyValueConflict(
1951c51afd54SEd Tanous                     asyncResp->res, "DateTime",
1952c51afd54SEd Tanous                     "Managers/NetworkProtocol/NTPProcotolEnabled");
1953c51afd54SEd Tanous                 return;
1954c51afd54SEd Tanous             }
1955c51afd54SEd Tanous         }
1956c51afd54SEd Tanous         messages::internalError(asyncResp->res);
1957c51afd54SEd Tanous         return;
1958c51afd54SEd Tanous     }
1959c51afd54SEd Tanous     asyncResp->res.result(boost::beast::http::status::no_content);
1960c51afd54SEd Tanous }
1961c51afd54SEd Tanous 
1962c51afd54SEd Tanous inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1963c51afd54SEd Tanous                         const std::string& datetime)
1964af5d6058SSantosh Puranik {
196562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
1966af5d6058SSantosh Puranik 
1967c2e32007SEd Tanous     std::optional<redfish::time_utils::usSinceEpoch> us =
1968c2e32007SEd Tanous         redfish::time_utils::dateStringToEpoch(datetime);
1969c2e32007SEd Tanous     if (!us)
1970af5d6058SSantosh Puranik     {
1971ac106bf6SEd Tanous         messages::propertyValueFormatError(asyncResp->res, datetime,
1972ac106bf6SEd Tanous                                            "DateTime");
1973c2e32007SEd Tanous         return;
1974c2e32007SEd Tanous     }
1975c51afd54SEd Tanous     // Set the absolute datetime
1976c51afd54SEd Tanous     bool relative = false;
1977c51afd54SEd Tanous     bool interactive = false;
1978c51afd54SEd Tanous     crow::connections::systemBus->async_method_call(
1979c51afd54SEd Tanous         [asyncResp](const boost::system::error_code& ec,
1980c51afd54SEd Tanous                     const sdbusplus::message_t& msg) {
1981c51afd54SEd Tanous             afterSetDateTime(asyncResp, ec, msg);
1982c51afd54SEd Tanous         },
1983c51afd54SEd Tanous         "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1984c51afd54SEd Tanous         "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1985c51afd54SEd Tanous         interactive);
198683ff9ab6SJames Feist }
19879c310685SBorawski.Lukasz 
198875815e5cSEd Tanous inline void
198975815e5cSEd Tanous     checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
199075815e5cSEd Tanous {
199175815e5cSEd Tanous     sdbusplus::asio::getProperty<std::string>(
199275815e5cSEd Tanous         *crow::connections::systemBus, "org.freedesktop.systemd1",
199375815e5cSEd Tanous         "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
199475815e5cSEd Tanous         "org.freedesktop.systemd1.Unit", "ActiveState",
199575815e5cSEd Tanous         [asyncResp](const boost::system::error_code& ec,
199675815e5cSEd Tanous                     const std::string& val) {
199775815e5cSEd Tanous             if (!ec)
199875815e5cSEd Tanous             {
199975815e5cSEd Tanous                 if (val == "active")
200075815e5cSEd Tanous                 {
2001539d8c6bSEd Tanous                     asyncResp->res.jsonValue["Status"]["Health"] =
2002539d8c6bSEd Tanous                         resource::Health::Critical;
2003539d8c6bSEd Tanous                     asyncResp->res.jsonValue["Status"]["State"] =
2004539d8c6bSEd Tanous                         resource::State::Quiesced;
200575815e5cSEd Tanous                     return;
200675815e5cSEd Tanous                 }
200775815e5cSEd Tanous             }
2008539d8c6bSEd Tanous             asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
2009bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Status"]["State"] =
2010bd79bce8SPatrick Williams                 resource::State::Enabled;
201175815e5cSEd Tanous         });
201275815e5cSEd Tanous }
201375815e5cSEd Tanous 
20147e860f15SJohn Edward Broadbent inline void requestRoutesManager(App& app)
20157e860f15SJohn Edward Broadbent {
20167e860f15SJohn Edward Broadbent     std::string uuid = persistent_data::getConfig().systemUuid;
20179c310685SBorawski.Lukasz 
2018253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
2019ed398213SEd Tanous         .privileges(redfish::privileges::getManager)
2020bd79bce8SPatrick Williams         .methods(
2021bd79bce8SPatrick Williams             boost::beast::http::verb::
2022bd79bce8SPatrick Williams                 get)([&app,
2023bd79bce8SPatrick Williams                       uuid](const crow::Request& req,
2024253f11b8SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2025253f11b8SEd Tanous                             const std::string& managerId) {
20263ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
202745ca1b86SEd Tanous             {
202845ca1b86SEd Tanous                 return;
202945ca1b86SEd Tanous             }
2030253f11b8SEd Tanous 
2031253f11b8SEd Tanous             if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2032253f11b8SEd Tanous             {
2033bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Manager",
2034bd79bce8SPatrick Williams                                            managerId);
2035253f11b8SEd Tanous                 return;
2036253f11b8SEd Tanous             }
2037253f11b8SEd Tanous 
2038253f11b8SEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2039253f11b8SEd Tanous                 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2040bd79bce8SPatrick Williams             asyncResp->res.jsonValue["@odata.type"] =
2041bd79bce8SPatrick Williams                 "#Manager.v1_14_0.Manager";
2042253f11b8SEd Tanous             asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
20437e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
20447e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Description"] =
20457e860f15SJohn Edward Broadbent                 "Baseboard Management Controller";
2046539d8c6bSEd Tanous             asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
20471476687dSEd Tanous 
2048539d8c6bSEd Tanous             asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
20497e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
20507e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2051bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Model"] =
2052bd79bce8SPatrick Williams                 "OpenBmc"; // TODO(ed), get model
20537e860f15SJohn Edward Broadbent 
20541476687dSEd Tanous             asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2055253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
2056253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20571476687dSEd Tanous             asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2058253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2059253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20601476687dSEd Tanous             asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2061bd79bce8SPatrick Williams                 boost::urls::format(
2062bd79bce8SPatrick Williams                     "/redfish/v1/Managers/{}/EthernetInterfaces",
2063253f11b8SEd Tanous                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20647e860f15SJohn Edward Broadbent 
206525b54dbaSEd Tanous             if constexpr (BMCWEB_VM_NBDPROXY)
206636c0f2a3SEd Tanous             {
20671476687dSEd Tanous                 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2068253f11b8SEd Tanous                     boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2069253f11b8SEd Tanous                                         BMCWEB_REDFISH_MANAGER_URI_NAME);
207036c0f2a3SEd Tanous             }
20717e860f15SJohn Edward Broadbent 
20727e860f15SJohn Edward Broadbent             // default oem data
20737e860f15SJohn Edward Broadbent             nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
20747e860f15SJohn Edward Broadbent             nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2075bd79bce8SPatrick Williams             oem["@odata.id"] =
2076bd79bce8SPatrick Williams                 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2077253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
2078fc1cdd14SEd Tanous             oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2079253f11b8SEd Tanous             oemOpenbmc["@odata.id"] =
2080253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2081253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20821476687dSEd Tanous 
20831476687dSEd Tanous             nlohmann::json::object_t certificates;
2084253f11b8SEd Tanous             certificates["@odata.id"] = boost::urls::format(
2085253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Truststore/Certificates",
2086253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
20871476687dSEd Tanous             oemOpenbmc["Certificates"] = std::move(certificates);
20887e860f15SJohn Edward Broadbent 
20897e860f15SJohn Edward Broadbent             // Manager.Reset (an action) can be many values, OpenBMC only
20907e860f15SJohn Edward Broadbent             // supports BMC reboot.
20917e860f15SJohn Edward Broadbent             nlohmann::json& managerReset =
20927e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2093bd79bce8SPatrick Williams             managerReset["target"] = boost::urls::format(
2094bd79bce8SPatrick Williams                 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2095253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
20967e860f15SJohn Edward Broadbent             managerReset["@Redfish.ActionInfo"] =
2097253f11b8SEd Tanous                 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2098253f11b8SEd Tanous                                     BMCWEB_REDFISH_MANAGER_URI_NAME);
20997e860f15SJohn Edward Broadbent 
21007e860f15SJohn Edward Broadbent             // ResetToDefaults (Factory Reset) has values like
21017e860f15SJohn Edward Broadbent             // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
21027e860f15SJohn Edward Broadbent             // on OpenBMC
21037e860f15SJohn Edward Broadbent             nlohmann::json& resetToDefaults =
21047e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2105253f11b8SEd Tanous             resetToDefaults["target"] = boost::urls::format(
2106253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2107253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
2108613dabeaSEd Tanous             resetToDefaults["ResetType@Redfish.AllowableValues"] =
2109613dabeaSEd Tanous                 nlohmann::json::array_t({"ResetAll"});
21107e860f15SJohn Edward Broadbent 
21117c8c4058STejas Patil             std::pair<std::string, std::string> redfishDateTimeOffset =
21122b82937eSEd Tanous                 redfish::time_utils::getDateTimeOffsetNow();
21137c8c4058STejas Patil 
21147c8c4058STejas Patil             asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
21157c8c4058STejas Patil             asyncResp->res.jsonValue["DateTimeLocalOffset"] =
21167c8c4058STejas Patil                 redfishDateTimeOffset.second;
21177e860f15SJohn Edward Broadbent 
21180e8ac5e7SGunnar Mills             // TODO (Gunnar): Remove these one day since moved to ComputerSystem
21190e8ac5e7SGunnar Mills             // Still used by OCP profiles
21200e8ac5e7SGunnar Mills             // https://github.com/opencomputeproject/OCP-Profiles/issues/23
21217e860f15SJohn Edward Broadbent             // Fill in SerialConsole info
21227e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["SerialConsole"]["ServiceEnabled"] = true;
2123bd79bce8SPatrick Williams             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2124bd79bce8SPatrick Williams                 15;
2125613dabeaSEd Tanous             asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] =
2126613dabeaSEd Tanous                 nlohmann::json::array_t({"IPMI", "SSH"});
212725b54dbaSEd Tanous             if constexpr (BMCWEB_KVM)
212825b54dbaSEd Tanous             {
21297e860f15SJohn Edward Broadbent                 // Fill in GraphicalConsole info
213025b54dbaSEd Tanous                 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
213125b54dbaSEd Tanous                     true;
213225b54dbaSEd Tanous                 asyncResp->res
213325b54dbaSEd Tanous                     .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
213425b54dbaSEd Tanous                 asyncResp->res
213525b54dbaSEd Tanous                     .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2136613dabeaSEd Tanous                     nlohmann::json::array_t({"KVMIP"});
213725b54dbaSEd Tanous             }
213825b54dbaSEd Tanous             if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
21397f3e84a1SEd Tanous             {
2140bd79bce8SPatrick Williams                 asyncResp->res
2141bd79bce8SPatrick Williams                     .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
21421476687dSEd Tanous 
21431476687dSEd Tanous                 nlohmann::json::array_t managerForServers;
21441476687dSEd Tanous                 nlohmann::json::object_t manager;
2145bd79bce8SPatrick Williams                 manager["@odata.id"] = std::format(
2146bd79bce8SPatrick Williams                     "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2147ad539545SPatrick Williams                 managerForServers.emplace_back(std::move(manager));
21481476687dSEd Tanous 
21491476687dSEd Tanous                 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
21501476687dSEd Tanous                     std::move(managerForServers);
21517f3e84a1SEd Tanous             }
21527e860f15SJohn Edward Broadbent 
2153eee0013eSWilly Tu             sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
21547e860f15SJohn Edward Broadbent                                                  "FirmwareVersion", true);
21557e860f15SJohn Edward Broadbent 
21567e860f15SJohn Edward Broadbent             managerGetLastResetTime(asyncResp);
21577e860f15SJohn Edward Broadbent 
2158a51fc2d2SSui Chen             // ManagerDiagnosticData is added for all BMCs.
2159a51fc2d2SSui Chen             nlohmann::json& managerDiagnosticData =
2160a51fc2d2SSui Chen                 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2161bd79bce8SPatrick Williams             managerDiagnosticData["@odata.id"] = boost::urls::format(
2162bd79bce8SPatrick Williams                 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2163253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
2164a51fc2d2SSui Chen 
216525b54dbaSEd Tanous             if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
216625b54dbaSEd Tanous             {
21677e860f15SJohn Edward Broadbent                 auto pids = std::make_shared<GetPIDValues>(asyncResp);
21687e860f15SJohn Edward Broadbent                 pids->run();
216925b54dbaSEd Tanous             }
21707e860f15SJohn Edward Broadbent 
2171bd79bce8SPatrick Williams             getMainChassisId(asyncResp, [](const std::string& chassisId,
2172bd79bce8SPatrick Williams                                            const std::shared_ptr<
2173bd79bce8SPatrick Williams                                                bmcweb::AsyncResp>& aRsp) {
2174bd79bce8SPatrick Williams                 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2175bd79bce8SPatrick Williams                     1;
21761476687dSEd Tanous                 nlohmann::json::array_t managerForChassis;
21778a592810SEd Tanous                 nlohmann::json::object_t managerObj;
2178ef4c65b7SEd Tanous                 boost::urls::url chassiUrl =
2179ef4c65b7SEd Tanous                     boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2180eddfc437SWilly Tu                 managerObj["@odata.id"] = chassiUrl;
2181ad539545SPatrick Williams                 managerForChassis.emplace_back(std::move(managerObj));
21821476687dSEd Tanous                 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
21831476687dSEd Tanous                     std::move(managerForChassis);
21841476687dSEd Tanous                 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2185eddfc437SWilly Tu                     chassiUrl;
21867e860f15SJohn Edward Broadbent             });
21877e860f15SJohn Edward Broadbent 
21881e1e598dSJonathan Doman             sdbusplus::asio::getProperty<double>(
21891e1e598dSJonathan Doman                 *crow::connections::systemBus, "org.freedesktop.systemd1",
2190002d39b4SEd Tanous                 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
2191002d39b4SEd Tanous                 "Progress",
219275815e5cSEd Tanous                 [asyncResp](const boost::system::error_code& ec, double val) {
21937e860f15SJohn Edward Broadbent                     if (ec)
21941abe55efSEd Tanous                     {
219562598e31SEd Tanous                         BMCWEB_LOG_ERROR("Error while getting progress");
21967e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
21977e860f15SJohn Edward Broadbent                         return;
21987e860f15SJohn Edward Broadbent                     }
21991e1e598dSJonathan Doman                     if (val < 1.0)
22007e860f15SJohn Edward Broadbent                     {
2201539d8c6bSEd Tanous                         asyncResp->res.jsonValue["Status"]["Health"] =
2202539d8c6bSEd Tanous                             resource::Health::OK;
2203539d8c6bSEd Tanous                         asyncResp->res.jsonValue["Status"]["State"] =
2204539d8c6bSEd Tanous                             resource::State::Starting;
220575815e5cSEd Tanous                         return;
22067e860f15SJohn Edward Broadbent                     }
220775815e5cSEd Tanous                     checkForQuiesced(asyncResp);
22081e1e598dSJonathan Doman                 });
22099c310685SBorawski.Lukasz 
2210e99073f5SGeorge Liu             constexpr std::array<std::string_view, 1> interfaces = {
2211e99073f5SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Bmc"};
2212e99073f5SGeorge Liu             dbus::utility::getSubTree(
2213e99073f5SGeorge Liu                 "/xyz/openbmc_project/inventory", 0, interfaces,
22147e860f15SJohn Edward Broadbent                 [asyncResp](
2215e99073f5SGeorge Liu                     const boost::system::error_code& ec,
2216b9d36b47SEd Tanous                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
22177e860f15SJohn Edward Broadbent                     if (ec)
22181abe55efSEd Tanous                     {
2219bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG(
2220bd79bce8SPatrick Williams                             "D-Bus response error on GetSubTree {}", ec);
22217e860f15SJohn Edward Broadbent                         return;
22227e860f15SJohn Edward Broadbent                     }
222326f6976fSEd Tanous                     if (subtree.empty())
22247e860f15SJohn Edward Broadbent                     {
222562598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
22267e860f15SJohn Edward Broadbent                         return;
22277e860f15SJohn Edward Broadbent                     }
22287e860f15SJohn Edward Broadbent                     // Assume only 1 bmc D-Bus object
22297e860f15SJohn Edward Broadbent                     // Throw an error if there is more than 1
22307e860f15SJohn Edward Broadbent                     if (subtree.size() > 1)
22317e860f15SJohn Edward Broadbent                     {
223262598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
22337e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
22347e860f15SJohn Edward Broadbent                         return;
22357e860f15SJohn Edward Broadbent                     }
22367e860f15SJohn Edward Broadbent 
2237bd79bce8SPatrick Williams                     if (subtree[0].first.empty() ||
2238bd79bce8SPatrick Williams                         subtree[0].second.size() != 1)
22397e860f15SJohn Edward Broadbent                     {
224062598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
22417e860f15SJohn Edward Broadbent                         messages::internalError(asyncResp->res);
22427e860f15SJohn Edward Broadbent                         return;
22437e860f15SJohn Edward Broadbent                     }
22447e860f15SJohn Edward Broadbent 
22457e860f15SJohn Edward Broadbent                     const std::string& path = subtree[0].first;
2246bd79bce8SPatrick Williams                     const std::string& connectionName =
2247bd79bce8SPatrick Williams                         subtree[0].second[0].first;
22487e860f15SJohn Edward Broadbent 
2249bd79bce8SPatrick Williams                     for (const auto& interfaceName :
2250bd79bce8SPatrick Williams                          subtree[0].second[0].second)
22517e860f15SJohn Edward Broadbent                     {
22527e860f15SJohn Edward Broadbent                         if (interfaceName ==
22537e860f15SJohn Edward Broadbent                             "xyz.openbmc_project.Inventory.Decorator.Asset")
22547e860f15SJohn Edward Broadbent                         {
2255fac6e53bSKrzysztof Grobelny                             sdbusplus::asio::getAllProperties(
2256bd79bce8SPatrick Williams                                 *crow::connections::systemBus, connectionName,
2257bd79bce8SPatrick Williams                                 path,
2258fac6e53bSKrzysztof Grobelny                                 "xyz.openbmc_project.Inventory.Decorator.Asset",
2259bd79bce8SPatrick Williams                                 [asyncResp](
2260bd79bce8SPatrick Williams                                     const boost::system::error_code& ec2,
2261b9d36b47SEd Tanous                                     const dbus::utility::DBusPropertiesMap&
22627e860f15SJohn Edward Broadbent                                         propertiesList) {
22638a592810SEd Tanous                                     if (ec2)
22647e860f15SJohn Edward Broadbent                                     {
2265bd79bce8SPatrick Williams                                         BMCWEB_LOG_DEBUG(
2266bd79bce8SPatrick Williams                                             "Can't get bmc asset!");
22677e860f15SJohn Edward Broadbent                                         return;
22687e860f15SJohn Edward Broadbent                                     }
22697e860f15SJohn Edward Broadbent 
2270fac6e53bSKrzysztof Grobelny                                     const std::string* partNumber = nullptr;
2271fac6e53bSKrzysztof Grobelny                                     const std::string* serialNumber = nullptr;
2272fac6e53bSKrzysztof Grobelny                                     const std::string* manufacturer = nullptr;
2273fac6e53bSKrzysztof Grobelny                                     const std::string* model = nullptr;
2274bd79bce8SPatrick Williams                                     const std::string* sparePartNumber =
2275bd79bce8SPatrick Williams                                         nullptr;
2276fac6e53bSKrzysztof Grobelny 
2277bd79bce8SPatrick Williams                                     const bool success =
2278bd79bce8SPatrick Williams                                         sdbusplus::unpackPropertiesNoThrow(
2279bd79bce8SPatrick Williams                                             dbus_utils::UnpackErrorPrinter(),
2280bd79bce8SPatrick Williams                                             propertiesList, "PartNumber",
2281bd79bce8SPatrick Williams                                             partNumber, "SerialNumber",
2282bd79bce8SPatrick Williams                                             serialNumber, "Manufacturer",
2283bd79bce8SPatrick Williams                                             manufacturer, "Model", model,
2284bd79bce8SPatrick Williams                                             "SparePartNumber", sparePartNumber);
2285fac6e53bSKrzysztof Grobelny 
2286fac6e53bSKrzysztof Grobelny                                     if (!success)
22877e860f15SJohn Edward Broadbent                                     {
2288002d39b4SEd Tanous                                         messages::internalError(asyncResp->res);
22897e860f15SJohn Edward Broadbent                                         return;
22907e860f15SJohn Edward Broadbent                                     }
2291fac6e53bSKrzysztof Grobelny 
2292fac6e53bSKrzysztof Grobelny                                     if (partNumber != nullptr)
2293fac6e53bSKrzysztof Grobelny                                     {
2294fac6e53bSKrzysztof Grobelny                                         asyncResp->res.jsonValue["PartNumber"] =
2295fac6e53bSKrzysztof Grobelny                                             *partNumber;
22967e860f15SJohn Edward Broadbent                                     }
2297fac6e53bSKrzysztof Grobelny 
2298fac6e53bSKrzysztof Grobelny                                     if (serialNumber != nullptr)
2299fac6e53bSKrzysztof Grobelny                                     {
2300bd79bce8SPatrick Williams                                         asyncResp->res
2301bd79bce8SPatrick Williams                                             .jsonValue["SerialNumber"] =
2302fac6e53bSKrzysztof Grobelny                                             *serialNumber;
23037e860f15SJohn Edward Broadbent                                     }
2304fac6e53bSKrzysztof Grobelny 
2305fac6e53bSKrzysztof Grobelny                                     if (manufacturer != nullptr)
2306fac6e53bSKrzysztof Grobelny                                     {
2307bd79bce8SPatrick Williams                                         asyncResp->res
2308bd79bce8SPatrick Williams                                             .jsonValue["Manufacturer"] =
2309fac6e53bSKrzysztof Grobelny                                             *manufacturer;
2310fac6e53bSKrzysztof Grobelny                                     }
2311fac6e53bSKrzysztof Grobelny 
2312fac6e53bSKrzysztof Grobelny                                     if (model != nullptr)
2313fac6e53bSKrzysztof Grobelny                                     {
2314bd79bce8SPatrick Williams                                         asyncResp->res.jsonValue["Model"] =
2315bd79bce8SPatrick Williams                                             *model;
2316fac6e53bSKrzysztof Grobelny                                     }
2317fac6e53bSKrzysztof Grobelny 
2318fac6e53bSKrzysztof Grobelny                                     if (sparePartNumber != nullptr)
2319fac6e53bSKrzysztof Grobelny                                     {
2320bd79bce8SPatrick Williams                                         asyncResp->res
2321bd79bce8SPatrick Williams                                             .jsonValue["SparePartNumber"] =
2322fac6e53bSKrzysztof Grobelny                                             *sparePartNumber;
2323fac6e53bSKrzysztof Grobelny                                     }
2324fac6e53bSKrzysztof Grobelny                                 });
23257e860f15SJohn Edward Broadbent                         }
2326bd79bce8SPatrick Williams                         else if (
2327bd79bce8SPatrick Williams                             interfaceName ==
23280fda0f12SGeorge Liu                             "xyz.openbmc_project.Inventory.Decorator.LocationCode")
23297e860f15SJohn Edward Broadbent                         {
23307e860f15SJohn Edward Broadbent                             getLocation(asyncResp, connectionName, path);
23317e860f15SJohn Edward Broadbent                         }
23327e860f15SJohn Edward Broadbent                     }
2333e99073f5SGeorge Liu                 });
23347e860f15SJohn Edward Broadbent         });
23357e860f15SJohn Edward Broadbent 
2336253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
2337ed398213SEd Tanous         .privileges(redfish::privileges::patchManager)
233845ca1b86SEd Tanous         .methods(boost::beast::http::verb::patch)(
233945ca1b86SEd Tanous             [&app](const crow::Request& req,
2340253f11b8SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2341253f11b8SEd Tanous                    const std::string& managerId) {
23423ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
234345ca1b86SEd Tanous                 {
234445ca1b86SEd Tanous                     return;
234545ca1b86SEd Tanous                 }
2346253f11b8SEd Tanous 
2347253f11b8SEd Tanous                 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2348253f11b8SEd Tanous                 {
2349bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Manager",
2350bd79bce8SPatrick Williams                                                managerId);
2351253f11b8SEd Tanous                     return;
2352253f11b8SEd Tanous                 }
2353253f11b8SEd Tanous 
23549e9b6049SEd Tanous                 std::optional<std::string> activeSoftwareImageOdataId;
23557e860f15SJohn Edward Broadbent                 std::optional<std::string> datetime;
23569e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> pidControllers;
23579e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> fanControllers;
23589e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> fanZones;
23599e9b6049SEd Tanous                 std::optional<nlohmann::json::object_t> stepwiseControllers;
23609e9b6049SEd Tanous                 std::optional<std::string> profile;
23617e860f15SJohn Edward Broadbent 
2362afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
2363afc474aeSMyung Bae                         req, asyncResp->res, //
2364afc474aeSMyung Bae                         "DateTime", datetime, //
2365afc474aeSMyung Bae                         "Links/ActiveSoftwareImage/@odata.id",
2366afc474aeSMyung Bae                         activeSoftwareImageOdataId, //
2367afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/FanControllers", fanControllers, //
2368afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/FanZones", fanZones, //
2369afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/PidControllers", pidControllers, //
2370afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/Profile", profile, //
2371afc474aeSMyung Bae                         "Oem/OpenBmc/Fan/StepwiseControllers",
2372afc474aeSMyung Bae                         stepwiseControllers //
23739e9b6049SEd Tanous                         ))
23747e860f15SJohn Edward Broadbent                 {
23757e860f15SJohn Edward Broadbent                     return;
23767e860f15SJohn Edward Broadbent                 }
23777e860f15SJohn Edward Broadbent 
23789e9b6049SEd Tanous                 if (pidControllers || fanControllers || fanZones ||
23799e9b6049SEd Tanous                     stepwiseControllers || profile)
23807e860f15SJohn Edward Broadbent                 {
238125b54dbaSEd Tanous                     if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
238225b54dbaSEd Tanous                     {
2383bd79bce8SPatrick Williams                         std::vector<
2384bd79bce8SPatrick Williams                             std::pair<std::string,
238525b54dbaSEd Tanous                                       std::optional<nlohmann::json::object_t>>>
23869e9b6049SEd Tanous                             configuration;
23879e9b6049SEd Tanous                         if (pidControllers)
23887e860f15SJohn Edward Broadbent                         {
2389bd79bce8SPatrick Williams                             configuration.emplace_back(
2390bd79bce8SPatrick Williams                                 "PidControllers", std::move(pidControllers));
23917e860f15SJohn Edward Broadbent                         }
23929e9b6049SEd Tanous                         if (fanControllers)
23937e860f15SJohn Edward Broadbent                         {
2394bd79bce8SPatrick Williams                             configuration.emplace_back(
2395bd79bce8SPatrick Williams                                 "FanControllers", std::move(fanControllers));
23967e860f15SJohn Edward Broadbent                         }
23979e9b6049SEd Tanous                         if (fanZones)
23987e860f15SJohn Edward Broadbent                         {
2399bd79bce8SPatrick Williams                             configuration.emplace_back("FanZones",
2400bd79bce8SPatrick Williams                                                        std::move(fanZones));
24019e9b6049SEd Tanous                         }
24029e9b6049SEd Tanous                         if (stepwiseControllers)
24039e9b6049SEd Tanous                         {
2404bd79bce8SPatrick Williams                             configuration.emplace_back(
2405bd79bce8SPatrick Williams                                 "StepwiseControllers",
24069e9b6049SEd Tanous                                 std::move(stepwiseControllers));
24079e9b6049SEd Tanous                         }
24089e9b6049SEd Tanous                         auto pid = std::make_shared<SetPIDValues>(
24099e9b6049SEd Tanous                             asyncResp, std::move(configuration), profile);
24107e860f15SJohn Edward Broadbent                         pid->run();
241125b54dbaSEd Tanous                     }
241225b54dbaSEd Tanous                     else
241325b54dbaSEd Tanous                     {
241454dce7f5SGunnar Mills                         messages::propertyUnknown(asyncResp->res, "Oem");
241554dce7f5SGunnar Mills                         return;
241625b54dbaSEd Tanous                     }
24177e860f15SJohn Edward Broadbent                 }
24189e9b6049SEd Tanous 
24199e9b6049SEd Tanous                 if (activeSoftwareImageOdataId)
24207e860f15SJohn Edward Broadbent                 {
2421bd79bce8SPatrick Williams                     setActiveFirmwareImage(asyncResp,
2422bd79bce8SPatrick Williams                                            *activeSoftwareImageOdataId);
24237e860f15SJohn Edward Broadbent                 }
24247e860f15SJohn Edward Broadbent 
24257e860f15SJohn Edward Broadbent                 if (datetime)
24267e860f15SJohn Edward Broadbent                 {
2427c51afd54SEd Tanous                     setDateTime(asyncResp, *datetime);
24287e860f15SJohn Edward Broadbent                 }
24297e860f15SJohn Edward Broadbent             });
24307e860f15SJohn Edward Broadbent }
24317e860f15SJohn Edward Broadbent 
24327e860f15SJohn Edward Broadbent inline void requestRoutesManagerCollection(App& app)
24337e860f15SJohn Edward Broadbent {
24347e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
2435ed398213SEd Tanous         .privileges(redfish::privileges::getManagerCollection)
24367e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
243745ca1b86SEd Tanous             [&app](const crow::Request& req,
24387e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
24393ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
244045ca1b86SEd Tanous                 {
244145ca1b86SEd Tanous                     return;
244245ca1b86SEd Tanous                 }
244383ff9ab6SJames Feist                 // Collections don't include the static data added by SubRoute
244483ff9ab6SJames Feist                 // because it has a duplicate entry for members
24458d1b46d7Szhanghch05                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
24468d1b46d7Szhanghch05                 asyncResp->res.jsonValue["@odata.type"] =
24478d1b46d7Szhanghch05                     "#ManagerCollection.ManagerCollection";
24488d1b46d7Szhanghch05                 asyncResp->res.jsonValue["Name"] = "Manager Collection";
24498d1b46d7Szhanghch05                 asyncResp->res.jsonValue["Members@odata.count"] = 1;
24501476687dSEd Tanous                 nlohmann::json::array_t members;
24511476687dSEd Tanous                 nlohmann::json& bmc = members.emplace_back();
2452bd79bce8SPatrick Williams                 bmc["@odata.id"] = boost::urls::format(
2453bd79bce8SPatrick Williams                     "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
24541476687dSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(members);
24557e860f15SJohn Edward Broadbent             });
24569c310685SBorawski.Lukasz }
24579c310685SBorawski.Lukasz } // namespace redfish
2458