blob: 33c992c442acc23e23f4fed8bb48562d5bce3b40 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01004#pragma once
5
Willy Tu13451e32023-05-24 16:08:18 -07006#include "bmcweb_config.h"
7
Sui Chena51fc2d2022-07-14 17:21:53 -07008#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "async_resp.hpp"
10#include "dbus_singleton.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070011#include "dbus_utility.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080012#include "error_messages.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070013#include "generated/enums/action_info.hpp"
14#include "generated/enums/manager.hpp"
15#include "generated/enums/resource.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080016#include "http_request.hpp"
17#include "logging.hpp"
18#include "persistent_data.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070019#include "query.hpp"
Jennifer Leec5d03ff2019-03-08 15:42:58 -080020#include "redfish_util.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070021#include "registries/privilege_registry.hpp"
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +020022#include "utils/dbus_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080023#include "utils/json_utils.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070024#include "utils/sw_utils.hpp"
25#include "utils/systemd_utils.hpp"
Ed Tanous2b829372022-08-03 14:22:34 -070026#include "utils/time_utils.hpp"
Borawski.Lukasz9c3106852018-02-09 15:24:22 +010027
Ed Tanousd7857202025-01-28 15:32:26 -080028#include <systemd/sd-bus.h>
29
30#include <boost/asio/post.hpp>
31#include <boost/beast/http/status.hpp>
32#include <boost/beast/http/verb.hpp>
33#include <boost/container/flat_map.hpp>
34#include <boost/container/flat_set.hpp>
George Liue99073f2022-12-09 11:06:16 +080035#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070036#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080037#include <boost/url/url.hpp>
38#include <nlohmann/json.hpp>
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +020039#include <sdbusplus/asio/property.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080040#include <sdbusplus/message.hpp>
41#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +020042#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050043
Ed Tanousa170f272022-06-30 21:53:27 -070044#include <algorithm>
George Liue99073f2022-12-09 11:06:16 +080045#include <array>
Ed Tanousd7857202025-01-28 15:32:26 -080046#include <cstddef>
Gunnar Mills4bfefa72020-07-30 13:54:29 -050047#include <cstdint>
Ed Tanousd7857202025-01-28 15:32:26 -080048#include <format>
49#include <functional>
50#include <map>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050051#include <memory>
Konstantin Aladyshev9970e932024-02-20 09:51:29 +030052#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070053#include <ranges>
Konstantin Aladyshev9970e932024-02-20 09:51:29 +030054#include <string>
George Liue99073f2022-12-09 11:06:16 +080055#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080056#include <utility>
Ed Tanousabf2add2019-01-22 16:40:12 -080057#include <variant>
Ed Tanousd7857202025-01-28 15:32:26 -080058#include <vector>
James Feist5b4aa862018-08-16 14:07:01 -070059
Ed Tanous1abe55e2018-09-05 08:30:59 -070060namespace redfish
61{
Jennifer Leeed5befb2018-08-10 11:29:45 -070062
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -070063inline std::string getBMCUpdateServiceName()
64{
65 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
66 {
67 return "xyz.openbmc_project.Software.Manager";
68 }
69 return "xyz.openbmc_project.Software.BMC.Updater";
70}
71
72inline std::string getBMCUpdateServicePath()
73{
74 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
75 {
76 return "/xyz/openbmc_project/software/bmc";
77 }
78 return "/xyz/openbmc_project/software";
79}
80
Jennifer Leeed5befb2018-08-10 11:29:45 -070081/**
Gunnar Mills2a5c4402020-05-19 09:07:24 -050082 * Function reboots the BMC.
83 *
84 * @param[in] asyncResp - Shared pointer for completing asynchronous calls
Jennifer Leeed5befb2018-08-10 11:29:45 -070085 */
zhanghch058d1b46d2021-04-01 11:18:24 +080086inline void
87 doBMCGracefulRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Gunnar Mills2a5c4402020-05-19 09:07:24 -050088{
89 const char* processName = "xyz.openbmc_project.State.BMC";
90 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
91 const char* interfaceName = "xyz.openbmc_project.State.BMC";
92 const std::string& propertyValue =
93 "xyz.openbmc_project.State.BMC.Transition.Reboot";
94 const char* destProperty = "RequestedBMCTransition";
95
96 // Create the D-Bus variant for D-Bus call.
George Liu9ae226f2023-06-21 17:56:46 +080097 sdbusplus::asio::setProperty(
98 *crow::connections::systemBus, processName, objectPath, interfaceName,
99 destProperty, propertyValue,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800100 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400101 // Use "Set" method to set the property value.
102 if (ec)
103 {
104 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
105 messages::internalError(asyncResp->res);
106 return;
107 }
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500108
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400109 messages::success(asyncResp->res);
110 });
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500111}
112
zhanghch058d1b46d2021-04-01 11:18:24 +0800113inline void
114 doBMCForceRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000115{
116 const char* processName = "xyz.openbmc_project.State.BMC";
117 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
118 const char* interfaceName = "xyz.openbmc_project.State.BMC";
119 const std::string& propertyValue =
120 "xyz.openbmc_project.State.BMC.Transition.HardReboot";
121 const char* destProperty = "RequestedBMCTransition";
122
123 // Create the D-Bus variant for D-Bus call.
George Liu9ae226f2023-06-21 17:56:46 +0800124 sdbusplus::asio::setProperty(
125 *crow::connections::systemBus, processName, objectPath, interfaceName,
126 destProperty, propertyValue,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800127 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400128 // Use "Set" method to set the property value.
129 if (ec)
130 {
131 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
132 messages::internalError(asyncResp->res);
133 return;
134 }
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000135
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400136 messages::success(asyncResp->res);
137 });
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000138}
139
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500140/**
141 * ManagerResetAction class supports the POST method for the Reset (reboot)
142 * action.
143 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700144inline void requestRoutesManagerResetAction(App& app)
Jennifer Leeed5befb2018-08-10 11:29:45 -0700145{
Jennifer Leeed5befb2018-08-10 11:29:45 -0700146 /**
Jennifer Leeed5befb2018-08-10 11:29:45 -0700147 * Function handles POST method request.
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500148 * Analyzes POST body before sending Reset (Reboot) request data to D-Bus.
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000149 * OpenBMC supports ResetType "GracefulRestart" and "ForceRestart".
Jennifer Leeed5befb2018-08-10 11:29:45 -0700150 */
Jennifer Leeed5befb2018-08-10 11:29:45 -0700151
Ed Tanous253f11b2024-05-16 09:38:31 -0700152 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Actions/Manager.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700153 .privileges(redfish::privileges::postManager)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700154 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700155 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700156 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
157 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400158 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
159 {
160 return;
161 }
162 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
163 {
164 messages::resourceNotFound(asyncResp->res, "Manager",
165 managerId);
166 return;
167 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700168
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400169 BMCWEB_LOG_DEBUG("Post Manager Reset.");
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500170
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400171 std::string resetType;
Jennifer Leeed5befb2018-08-10 11:29:45 -0700172
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400173 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
174 resetType))
175 {
176 return;
177 }
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500178
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400179 if (resetType == "GracefulRestart")
180 {
181 BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
182 doBMCGracefulRestart(asyncResp);
183 return;
184 }
185 if (resetType == "ForceRestart")
186 {
187 BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
188 doBMCForceRestart(asyncResp);
189 return;
190 }
191 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
192 resetType);
193 messages::actionParameterNotSupported(asyncResp->res, resetType,
194 "ResetType");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700195
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400196 return;
197 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700198}
Jennifer Leeed5befb2018-08-10 11:29:45 -0700199
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500200/**
201 * ManagerResetToDefaultsAction class supports POST method for factory reset
202 * action.
203 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700204inline void requestRoutesManagerResetToDefaultsAction(App& app)
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500205{
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500206 /**
207 * Function handles ResetToDefaults POST method request.
208 *
209 * Analyzes POST body message and factory resets BMC by calling
210 * BMC code updater factory reset followed by a BMC reboot.
211 *
212 * BMC code updater factory reset wipes the whole BMC read-write
213 * filesystem which includes things like the network settings.
214 *
215 * OpenBMC only supports ResetToDefaultsType "ResetAll".
216 */
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500217
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700218 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -0700219 "/redfish/v1/Managers/<str>/Actions/Manager.ResetToDefaults/")
Ed Tanoused398212021-06-09 17:05:54 -0700220 .privileges(redfish::privileges::postManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400221 .methods(
222 boost::beast::http::verb::
223 post)([&app](
224 const crow::Request& req,
225 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
226 const std::string& managerId) {
227 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700228 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700229 return;
230 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400231
232 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
233 {
234 messages::resourceNotFound(asyncResp->res, "Manager",
235 managerId);
236 return;
237 }
238
239 BMCWEB_LOG_DEBUG("Post ResetToDefaults.");
240
241 std::optional<std::string> resetType;
242 std::optional<std::string> resetToDefaultsType;
243
Myung Baeafc474a2024-10-09 00:53:29 -0700244 if (!json_util::readJsonAction( //
245 req, asyncResp->res, //
246 "ResetToDefaultsType", resetToDefaultsType, //
247 "ResetType", resetType //
248 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400249 {
250 BMCWEB_LOG_DEBUG("Missing property ResetType.");
251
252 messages::actionParameterMissing(
253 asyncResp->res, "ResetToDefaults", "ResetType");
254 return;
255 }
256
257 if (resetToDefaultsType && !resetType)
258 {
259 BMCWEB_LOG_WARNING(
260 "Using deprecated ResetToDefaultsType, should be ResetType."
261 "Support for the ResetToDefaultsType will be dropped in 2Q24");
262 resetType = resetToDefaultsType;
263 }
264
265 if (resetType != "ResetAll")
266 {
267 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
268 *resetType);
269 messages::actionParameterNotSupported(asyncResp->res,
270 *resetType, "ResetType");
271 return;
272 }
273
274 crow::connections::systemBus->async_method_call(
275 [asyncResp](const boost::system::error_code& ec) {
276 if (ec)
277 {
278 BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec);
279 messages::internalError(asyncResp->res);
280 return;
281 }
282 // Factory Reset doesn't actually happen until a reboot
283 // Can't erase what the BMC is running on
284 doBMCGracefulRestart(asyncResp);
285 },
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -0700286 getBMCUpdateServiceName(), getBMCUpdateServicePath(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400287 "xyz.openbmc_project.Common.FactoryReset", "Reset");
288 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700289}
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500290
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530291/**
292 * ManagerResetActionInfo derived class for delivering Manager
293 * ResetType AllowableValues using ResetInfo schema.
294 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700295inline void requestRoutesManagerResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530296{
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530297 /**
298 * Functions triggers appropriate requests on DBus
299 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700300
Ed Tanous253f11b2024-05-16 09:38:31 -0700301 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700302 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700303 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700304 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700305 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
306 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400307 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
308 {
309 return;
310 }
Ed Tanous14766872022-03-15 10:44:42 -0700311
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400312 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
313 {
314 messages::resourceNotFound(asyncResp->res, "Manager",
315 managerId);
316 return;
317 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700318
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400319 asyncResp->res.jsonValue["@odata.type"] =
320 "#ActionInfo.v1_1_2.ActionInfo";
321 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
322 "/redfish/v1/Managers/{}/ResetActionInfo",
323 BMCWEB_REDFISH_MANAGER_URI_NAME);
324 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
325 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
326 nlohmann::json::object_t parameter;
327 parameter["Name"] = "ResetType";
328 parameter["Required"] = true;
329 parameter["DataType"] = action_info::ParameterTypes::String;
Ed Tanous14766872022-03-15 10:44:42 -0700330
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400331 nlohmann::json::array_t allowableValues;
332 allowableValues.emplace_back("GracefulRestart");
333 allowableValues.emplace_back("ForceRestart");
334 parameter["AllowableValues"] = std::move(allowableValues);
Ed Tanous14766872022-03-15 10:44:42 -0700335
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400336 nlohmann::json::array_t parameters;
337 parameters.emplace_back(std::move(parameter));
Ed Tanous14766872022-03-15 10:44:42 -0700338
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400339 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
340 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700341}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530342
James Feist5b4aa862018-08-16 14:07:01 -0700343static constexpr const char* objectManagerIface =
344 "org.freedesktop.DBus.ObjectManager";
345static constexpr const char* pidConfigurationIface =
346 "xyz.openbmc_project.Configuration.Pid";
347static constexpr const char* pidZoneConfigurationIface =
348 "xyz.openbmc_project.Configuration.Pid.Zone";
James Feistb7a08d02018-12-11 14:55:37 -0800349static constexpr const char* stepwiseConfigurationIface =
350 "xyz.openbmc_project.Configuration.Stepwise";
James Feist73df0db2019-03-25 15:29:35 -0700351static constexpr const char* thermalModeIface =
352 "xyz.openbmc_project.Control.ThermalMode";
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100353
zhanghch058d1b46d2021-04-01 11:18:24 +0800354inline void
355 asyncPopulatePid(const std::string& connection, const std::string& path,
356 const std::string& currentProfile,
357 const std::vector<std::string>& supportedProfiles,
358 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
James Feist5b4aa862018-08-16 14:07:01 -0700359{
George Liu5eb468d2023-06-20 17:03:24 +0800360 sdbusplus::message::object_path objPath(path);
361 dbus::utility::getManagedObjects(
362 connection, objPath,
James Feist73df0db2019-03-25 15:29:35 -0700363 [asyncResp, currentProfile, supportedProfiles](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800364 const boost::system::error_code& ec,
James Feist73df0db2019-03-25 15:29:35 -0700365 const dbus::utility::ManagedObjectType& managedObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400366 if (ec)
James Feist5b4aa862018-08-16 14:07:01 -0700367 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400368 BMCWEB_LOG_ERROR("{}", ec);
369 messages::internalError(asyncResp->res);
370 return;
371 }
372 nlohmann::json& configRoot =
373 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
374 nlohmann::json& fans = configRoot["FanControllers"];
375 fans["@odata.type"] =
376 "#OpenBMCManager.v1_0_0.Manager.FanControllers";
377 fans["@odata.id"] = boost::urls::format(
378 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
379 BMCWEB_REDFISH_MANAGER_URI_NAME);
380
381 nlohmann::json& pids = configRoot["PidControllers"];
382 pids["@odata.type"] =
383 "#OpenBMCManager.v1_0_0.Manager.PidControllers";
384 pids["@odata.id"] = boost::urls::format(
385 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
386 BMCWEB_REDFISH_MANAGER_URI_NAME);
387
388 nlohmann::json& stepwise = configRoot["StepwiseControllers"];
389 stepwise["@odata.type"] =
390 "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
391 stepwise["@odata.id"] = boost::urls::format(
392 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
393 BMCWEB_REDFISH_MANAGER_URI_NAME);
394
395 nlohmann::json& zones = configRoot["FanZones"];
396 zones["@odata.id"] = boost::urls::format(
397 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
398 BMCWEB_REDFISH_MANAGER_URI_NAME);
399 zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
400 configRoot["@odata.id"] =
401 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
402 BMCWEB_REDFISH_MANAGER_URI_NAME);
403 configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
404 configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
405
406 if (!currentProfile.empty())
407 {
408 configRoot["Profile"] = currentProfile;
409 }
410 BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
411
412 for (const auto& pathPair : managedObj)
413 {
414 for (const auto& intfPair : pathPair.second)
James Feist5b4aa862018-08-16 14:07:01 -0700415 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400416 if (intfPair.first != pidConfigurationIface &&
417 intfPair.first != pidZoneConfigurationIface &&
418 intfPair.first != stepwiseConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 {
420 continue;
421 }
422
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400423 std::string name;
424
425 for (const std::pair<std::string,
426 dbus::utility::DbusVariantType>&
427 propPair : intfPair.second)
428 {
429 if (propPair.first == "Name")
430 {
431 const std::string* namePtr =
432 std::get_if<std::string>(&propPair.second);
433 if (namePtr == nullptr)
434 {
435 BMCWEB_LOG_ERROR("Pid Name Field illegal");
436 messages::internalError(asyncResp->res);
437 return;
438 }
439 name = *namePtr;
440 dbus::utility::escapePathForDbus(name);
441 }
442 else if (propPair.first == "Profiles")
443 {
444 const std::vector<std::string>* profiles =
445 std::get_if<std::vector<std::string>>(
446 &propPair.second);
447 if (profiles == nullptr)
448 {
449 BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
450 messages::internalError(asyncResp->res);
451 return;
452 }
453 if (std::find(profiles->begin(), profiles->end(),
454 currentProfile) == profiles->end())
455 {
456 BMCWEB_LOG_INFO(
457 "{} not supported in current profile",
458 name);
459 continue;
460 }
461 }
462 }
463 nlohmann::json* config = nullptr;
464 const std::string* classPtr = nullptr;
465
466 for (const std::pair<std::string,
467 dbus::utility::DbusVariantType>&
468 propPair : intfPair.second)
469 {
470 if (propPair.first == "Class")
471 {
472 classPtr =
473 std::get_if<std::string>(&propPair.second);
474 }
475 }
476
477 boost::urls::url url(
478 boost::urls::format("/redfish/v1/Managers/{}",
479 BMCWEB_REDFISH_MANAGER_URI_NAME));
Ed Tanous002d39b2022-05-31 08:59:27 -0700480 if (intfPair.first == pidZoneConfigurationIface)
481 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400482 std::string chassis;
483 if (!dbus::utility::getNthStringFromPath(
484 pathPair.first.str, 5, chassis))
Ed Tanous002d39b2022-05-31 08:59:27 -0700485 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400486 chassis = "#IllegalValue";
487 }
488 nlohmann::json& zone = zones[name];
489 zone["Chassis"]["@odata.id"] = boost::urls::format(
490 "/redfish/v1/Chassis/{}", chassis);
491 url.set_fragment(
492 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
493 .to_string());
494 zone["@odata.id"] = std::move(url);
495 zone["@odata.type"] =
496 "#OpenBMCManager.v1_0_0.Manager.FanZone";
497 config = &zone;
498 }
499
500 else if (intfPair.first == stepwiseConfigurationIface)
501 {
502 if (classPtr == nullptr)
503 {
504 BMCWEB_LOG_ERROR("Pid Class Field illegal");
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 messages::internalError(asyncResp->res);
506 return;
507 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700508
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400509 nlohmann::json& controller = stepwise[name];
510 config = &controller;
511 url.set_fragment(
512 ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
513 name)
514 .to_string());
515 controller["@odata.id"] = std::move(url);
516 controller["@odata.type"] =
517 "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700518
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400519 controller["Direction"] = *classPtr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 }
James Feistb7a08d02018-12-11 14:55:37 -0800521
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 // pid and fans are off the same configuration
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400523 else if (intfPair.first == pidConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700524 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400525 if (classPtr == nullptr)
James Feistb7a08d02018-12-11 14:55:37 -0800526 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400527 BMCWEB_LOG_ERROR("Pid Class Field illegal");
528 messages::internalError(asyncResp->res);
529 return;
James Feist5b4aa862018-08-16 14:07:01 -0700530 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400531 bool isFan = *classPtr == "fan";
532 nlohmann::json& element =
533 isFan ? fans[name] : pids[name];
534 config = &element;
535 if (isFan)
James Feist5b4aa862018-08-16 14:07:01 -0700536 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400537 url.set_fragment(
538 ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
539 name)
540 .to_string());
541 element["@odata.id"] = std::move(url);
542 element["@odata.type"] =
543 "#OpenBMCManager.v1_0_0.Manager.FanController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700544 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400545 else
Ed Tanous002d39b2022-05-31 08:59:27 -0700546 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400547 url.set_fragment(
548 ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
549 name)
550 .to_string());
551 element["@odata.id"] = std::move(url);
552 element["@odata.type"] =
553 "#OpenBMCManager.v1_0_0.Manager.PidController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700554 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400555 }
556 else
557 {
558 BMCWEB_LOG_ERROR("Unexpected configuration");
559 messages::internalError(asyncResp->res);
560 return;
561 }
562
563 // used for making maps out of 2 vectors
564 const std::vector<double>* keys = nullptr;
565 const std::vector<double>* values = nullptr;
566
567 for (const auto& propertyPair : intfPair.second)
568 {
569 if (propertyPair.first == "Type" ||
570 propertyPair.first == "Class" ||
571 propertyPair.first == "Name")
572 {
573 continue;
574 }
575
576 // zones
577 if (intfPair.first == pidZoneConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700578 {
579 const double* ptr =
580 std::get_if<double>(&propertyPair.second);
581 if (ptr == nullptr)
582 {
Ed Tanous62598e32023-07-17 17:06:25 -0700583 BMCWEB_LOG_ERROR("Field Illegal {}",
584 propertyPair.first);
Ed Tanous002d39b2022-05-31 08:59:27 -0700585 messages::internalError(asyncResp->res);
586 return;
587 }
588 (*config)[propertyPair.first] = *ptr;
James Feist5b4aa862018-08-16 14:07:01 -0700589 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400590
591 if (intfPair.first == stepwiseConfigurationIface)
592 {
593 if (propertyPair.first == "Reading" ||
594 propertyPair.first == "Output")
595 {
596 const std::vector<double>* ptr =
597 std::get_if<std::vector<double>>(
598 &propertyPair.second);
599
600 if (ptr == nullptr)
601 {
602 BMCWEB_LOG_ERROR("Field Illegal {}",
603 propertyPair.first);
604 messages::internalError(asyncResp->res);
605 return;
606 }
607
608 if (propertyPair.first == "Reading")
609 {
610 keys = ptr;
611 }
612 else
613 {
614 values = ptr;
615 }
616 if (keys != nullptr && values != nullptr)
617 {
618 if (keys->size() != values->size())
619 {
620 BMCWEB_LOG_ERROR(
621 "Reading and Output size don't match ");
622 messages::internalError(asyncResp->res);
623 return;
624 }
625 nlohmann::json& steps = (*config)["Steps"];
626 steps = nlohmann::json::array();
627 for (size_t ii = 0; ii < keys->size(); ii++)
628 {
629 nlohmann::json::object_t step;
630 step["Target"] = (*keys)[ii];
631 step["Output"] = (*values)[ii];
632 steps.emplace_back(std::move(step));
633 }
634 }
635 }
636 if (propertyPair.first == "NegativeHysteresis" ||
637 propertyPair.first == "PositiveHysteresis")
638 {
639 const double* ptr =
640 std::get_if<double>(&propertyPair.second);
641 if (ptr == nullptr)
642 {
643 BMCWEB_LOG_ERROR("Field Illegal {}",
644 propertyPair.first);
645 messages::internalError(asyncResp->res);
646 return;
647 }
648 (*config)[propertyPair.first] = *ptr;
649 }
650 }
651
652 // pid and fans are off the same configuration
653 if (intfPair.first == pidConfigurationIface ||
654 intfPair.first == stepwiseConfigurationIface)
655 {
656 if (propertyPair.first == "Zones")
657 {
658 const std::vector<std::string>* inputs =
659 std::get_if<std::vector<std::string>>(
660 &propertyPair.second);
661
662 if (inputs == nullptr)
663 {
664 BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
665 messages::internalError(asyncResp->res);
666 return;
667 }
668 auto& data = (*config)[propertyPair.first];
669 data = nlohmann::json::array();
670 for (std::string itemCopy : *inputs)
671 {
672 dbus::utility::escapePathForDbus(itemCopy);
673 nlohmann::json::object_t input;
674 boost::urls::url managerUrl =
675 boost::urls::format(
676 "/redfish/v1/Managers/{}#{}",
677 BMCWEB_REDFISH_MANAGER_URI_NAME,
678 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
679 itemCopy)
680 .to_string());
681 input["@odata.id"] = std::move(managerUrl);
682 data.emplace_back(std::move(input));
683 }
684 }
685 // todo(james): may never happen, but this
686 // assumes configuration data referenced in the
687 // PID config is provided by the same daemon, we
688 // could add another loop to cover all cases,
689 // but I'm okay kicking this can down the road a
690 // bit
691
692 else if (propertyPair.first == "Inputs" ||
693 propertyPair.first == "Outputs")
694 {
695 auto& data = (*config)[propertyPair.first];
696 const std::vector<std::string>* inputs =
697 std::get_if<std::vector<std::string>>(
698 &propertyPair.second);
699
700 if (inputs == nullptr)
701 {
702 BMCWEB_LOG_ERROR("Field Illegal {}",
703 propertyPair.first);
704 messages::internalError(asyncResp->res);
705 return;
706 }
707 data = *inputs;
708 }
709 else if (propertyPair.first == "SetPointOffset")
710 {
711 const std::string* ptr =
712 std::get_if<std::string>(
713 &propertyPair.second);
714
715 if (ptr == nullptr)
716 {
717 BMCWEB_LOG_ERROR("Field Illegal {}",
718 propertyPair.first);
719 messages::internalError(asyncResp->res);
720 return;
721 }
722 // translate from dbus to redfish
723 if (*ptr == "WarningHigh")
724 {
725 (*config)["SetPointOffset"] =
726 "UpperThresholdNonCritical";
727 }
728 else if (*ptr == "WarningLow")
729 {
730 (*config)["SetPointOffset"] =
731 "LowerThresholdNonCritical";
732 }
733 else if (*ptr == "CriticalHigh")
734 {
735 (*config)["SetPointOffset"] =
736 "UpperThresholdCritical";
737 }
738 else if (*ptr == "CriticalLow")
739 {
740 (*config)["SetPointOffset"] =
741 "LowerThresholdCritical";
742 }
743 else
744 {
745 BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
746 messages::internalError(asyncResp->res);
747 return;
748 }
749 }
750 // doubles
751 else if (propertyPair.first ==
752 "FFGainCoefficient" ||
753 propertyPair.first == "FFOffCoefficient" ||
754 propertyPair.first == "ICoefficient" ||
755 propertyPair.first == "ILimitMax" ||
756 propertyPair.first == "ILimitMin" ||
757 propertyPair.first ==
758 "PositiveHysteresis" ||
759 propertyPair.first ==
760 "NegativeHysteresis" ||
761 propertyPair.first == "OutLimitMax" ||
762 propertyPair.first == "OutLimitMin" ||
763 propertyPair.first == "PCoefficient" ||
764 propertyPair.first == "SetPoint" ||
765 propertyPair.first == "SlewNeg" ||
766 propertyPair.first == "SlewPos")
767 {
768 const double* ptr =
769 std::get_if<double>(&propertyPair.second);
770 if (ptr == nullptr)
771 {
772 BMCWEB_LOG_ERROR("Field Illegal {}",
773 propertyPair.first);
774 messages::internalError(asyncResp->res);
775 return;
776 }
777 (*config)[propertyPair.first] = *ptr;
778 }
779 }
James Feist5b4aa862018-08-16 14:07:01 -0700780 }
781 }
782 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400783 });
James Feist5b4aa862018-08-16 14:07:01 -0700784}
Jennifer Leeca537922018-08-10 10:07:30 -0700785
James Feist83ff9ab2018-08-31 10:18:24 -0700786enum class CreatePIDRet
787{
788 fail,
789 del,
790 patch
791};
792
zhanghch058d1b46d2021-04-01 11:18:24 +0800793inline bool
794 getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800795 std::vector<nlohmann::json::object_t>& config,
zhanghch058d1b46d2021-04-01 11:18:24 +0800796 std::vector<std::string>& zones)
James Feist5f2caae2018-12-12 14:08:25 -0800797{
James Feistb6baeaa2019-02-21 10:41:40 -0800798 if (config.empty())
799 {
Ed Tanous62598e32023-07-17 17:06:25 -0700800 BMCWEB_LOG_ERROR("Empty Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700801 messages::propertyValueFormatError(response->res, config, "Zones");
James Feistb6baeaa2019-02-21 10:41:40 -0800802 return false;
803 }
James Feist5f2caae2018-12-12 14:08:25 -0800804 for (auto& odata : config)
805 {
806 std::string path;
Ed Tanous9e9b6042024-03-06 14:18:28 -0800807 if (!redfish::json_util::readJsonObject(odata, response->res,
808 "@odata.id", path))
James Feist5f2caae2018-12-12 14:08:25 -0800809 {
810 return false;
811 }
812 std::string input;
James Feist61adbda2019-03-25 13:03:51 -0700813
814 // 8 below comes from
815 // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
816 // 0 1 2 3 4 5 6 7 8
817 if (!dbus::utility::getNthStringFromPath(path, 8, input))
James Feist5f2caae2018-12-12 14:08:25 -0800818 {
Ed Tanous62598e32023-07-17 17:06:25 -0700819 BMCWEB_LOG_ERROR("Got invalid path {}", path);
820 BMCWEB_LOG_ERROR("Illegal Type Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700821 messages::propertyValueFormatError(response->res, odata, "Zones");
James Feist5f2caae2018-12-12 14:08:25 -0800822 return false;
823 }
Ed Tanousa170f272022-06-30 21:53:27 -0700824 std::replace(input.begin(), input.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -0800825 zones.emplace_back(std::move(input));
826 }
827 return true;
828}
829
Ed Tanous711ac7a2021-12-20 09:34:41 -0800830inline const dbus::utility::ManagedObjectType::value_type*
James Feist73df0db2019-03-25 15:29:35 -0700831 findChassis(const dbus::utility::ManagedObjectType& managedObj,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800832 std::string_view value, std::string& chassis)
James Feistb6baeaa2019-02-21 10:41:40 -0800833{
Ed Tanous62598e32023-07-17 17:06:25 -0700834 BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
James Feistb6baeaa2019-02-21 10:41:40 -0800835
Ed Tanous9e9b6042024-03-06 14:18:28 -0800836 std::string escaped(value);
Yaswanth Reddy M6ce82fa2023-03-10 07:29:45 +0000837 std::replace(escaped.begin(), escaped.end(), ' ', '_');
James Feistb6baeaa2019-02-21 10:41:40 -0800838 escaped = "/" + escaped;
Ed Tanous3544d2a2023-08-06 18:12:20 -0700839 auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
Ed Tanous18f8f602023-07-18 10:07:23 -0700840 if (obj.first.str.ends_with(escaped))
Ed Tanous002d39b2022-05-31 08:59:27 -0700841 {
Ed Tanous62598e32023-07-17 17:06:25 -0700842 BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700843 return true;
844 }
845 return false;
846 });
James Feistb6baeaa2019-02-21 10:41:40 -0800847
848 if (it == managedObj.end())
849 {
James Feist73df0db2019-03-25 15:29:35 -0700850 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800851 }
852 // 5 comes from <chassis-name> being the 5th element
853 // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
James Feist73df0db2019-03-25 15:29:35 -0700854 if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
855 {
856 return &(*it);
857 }
858
859 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800860}
861
Ed Tanous23a21a12020-07-25 04:45:05 +0000862inline CreatePIDRet createPidInterface(
zhanghch058d1b46d2021-04-01 11:18:24 +0800863 const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800864 std::string_view name, nlohmann::json& jsonValue, const std::string& path,
James Feist83ff9ab2018-08-31 10:18:24 -0700865 const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800866 dbus::utility::DBusPropertiesMap& output, std::string& chassis,
867 const std::string& profile)
James Feist83ff9ab2018-08-31 10:18:24 -0700868{
James Feist5f2caae2018-12-12 14:08:25 -0800869 // common deleter
Ed Tanous9e9b6042024-03-06 14:18:28 -0800870 if (jsonValue == nullptr)
James Feist5f2caae2018-12-12 14:08:25 -0800871 {
872 std::string iface;
873 if (type == "PidControllers" || type == "FanControllers")
874 {
875 iface = pidConfigurationIface;
876 }
877 else if (type == "FanZones")
878 {
879 iface = pidZoneConfigurationIface;
880 }
881 else if (type == "StepwiseControllers")
882 {
883 iface = stepwiseConfigurationIface;
884 }
885 else
886 {
Ed Tanous62598e32023-07-17 17:06:25 -0700887 BMCWEB_LOG_ERROR("Illegal Type {}", type);
James Feist5f2caae2018-12-12 14:08:25 -0800888 messages::propertyUnknown(response->res, type);
889 return CreatePIDRet::fail;
890 }
James Feist6ee7f772020-02-06 16:25:27 -0800891
Ed Tanous62598e32023-07-17 17:06:25 -0700892 BMCWEB_LOG_DEBUG("del {} {}", path, iface);
James Feist5f2caae2018-12-12 14:08:25 -0800893 // delete interface
894 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800895 [response, path](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400896 if (ec)
897 {
898 BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
899 messages::internalError(response->res);
900 return;
901 }
902 messages::success(response->res);
903 },
James Feist5f2caae2018-12-12 14:08:25 -0800904 "xyz.openbmc_project.EntityManager", path, iface, "Delete");
905 return CreatePIDRet::del;
906 }
907
Ed Tanous711ac7a2021-12-20 09:34:41 -0800908 const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800909 if (!createNewObject)
910 {
911 // if we aren't creating a new object, we should be able to find it on
912 // d-bus
Ed Tanous9e9b6042024-03-06 14:18:28 -0800913 managedItem = findChassis(managedObj, name, chassis);
James Feist73df0db2019-03-25 15:29:35 -0700914 if (managedItem == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -0800915 {
Ed Tanous62598e32023-07-17 17:06:25 -0700916 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousef4c65b2023-04-24 15:28:50 -0700917 messages::invalidObject(
918 response->res,
919 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -0800920 return CreatePIDRet::fail;
921 }
922 }
923
Ed Tanous26f69762022-01-25 09:49:11 -0800924 if (!profile.empty() &&
James Feist73df0db2019-03-25 15:29:35 -0700925 (type == "PidControllers" || type == "FanControllers" ||
926 type == "StepwiseControllers"))
927 {
928 if (managedItem == nullptr)
929 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800930 output.emplace_back("Profiles", std::vector<std::string>{profile});
James Feist73df0db2019-03-25 15:29:35 -0700931 }
932 else
933 {
934 std::string interface;
935 if (type == "StepwiseControllers")
936 {
937 interface = stepwiseConfigurationIface;
938 }
939 else
940 {
941 interface = pidConfigurationIface;
942 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800943 bool ifaceFound = false;
944 for (const auto& iface : managedItem->second)
945 {
946 if (iface.first == interface)
947 {
948 ifaceFound = true;
949 for (const auto& prop : iface.second)
950 {
951 if (prop.first == "Profiles")
952 {
953 const std::vector<std::string>* curProfiles =
954 std::get_if<std::vector<std::string>>(
955 &(prop.second));
956 if (curProfiles == nullptr)
957 {
Ed Tanous62598e32023-07-17 17:06:25 -0700958 BMCWEB_LOG_ERROR(
959 "Illegal profiles in managed object");
Ed Tanous711ac7a2021-12-20 09:34:41 -0800960 messages::internalError(response->res);
961 return CreatePIDRet::fail;
962 }
963 if (std::find(curProfiles->begin(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400964 curProfiles->end(), profile) ==
965 curProfiles->end())
Ed Tanous711ac7a2021-12-20 09:34:41 -0800966 {
967 std::vector<std::string> newProfiles =
968 *curProfiles;
969 newProfiles.push_back(profile);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800970 output.emplace_back("Profiles", newProfiles);
Ed Tanous711ac7a2021-12-20 09:34:41 -0800971 }
972 }
973 }
974 }
975 }
976
977 if (!ifaceFound)
James Feist73df0db2019-03-25 15:29:35 -0700978 {
Ed Tanous62598e32023-07-17 17:06:25 -0700979 BMCWEB_LOG_ERROR("Failed to find interface in managed object");
James Feist73df0db2019-03-25 15:29:35 -0700980 messages::internalError(response->res);
981 return CreatePIDRet::fail;
982 }
James Feist73df0db2019-03-25 15:29:35 -0700983 }
984 }
985
James Feist83ff9ab2018-08-31 10:18:24 -0700986 if (type == "PidControllers" || type == "FanControllers")
987 {
988 if (createNewObject)
989 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800990 output.emplace_back("Class",
991 type == "PidControllers" ? "temp" : "fan");
992 output.emplace_back("Type", "Pid");
James Feist83ff9ab2018-08-31 10:18:24 -0700993 }
James Feist5f2caae2018-12-12 14:08:25 -0800994
Ed Tanous9e9b6042024-03-06 14:18:28 -0800995 std::optional<std::vector<nlohmann::json::object_t>> zones;
James Feist5f2caae2018-12-12 14:08:25 -0800996 std::optional<std::vector<std::string>> inputs;
997 std::optional<std::vector<std::string>> outputs;
998 std::map<std::string, std::optional<double>> doubles;
James Feistb943aae2019-07-11 16:33:56 -0700999 std::optional<std::string> setpointOffset;
Myung Baeafc474a2024-10-09 00:53:29 -07001000 if (!redfish::json_util::readJson( //
1001 jsonValue, response->res, //
1002 "FFGainCoefficient", doubles["FFGainCoefficient"], //
1003 "FFOffCoefficient", doubles["FFOffCoefficient"], //
1004 "ICoefficient", doubles["ICoefficient"], //
1005 "ILimitMax", doubles["ILimitMax"], //
1006 "ILimitMin", doubles["ILimitMin"], //
1007 "Inputs", inputs, //
1008 "NegativeHysteresis", doubles["NegativeHysteresis"], //
1009 "OutLimitMax", doubles["OutLimitMax"], //
1010 "OutLimitMin", doubles["OutLimitMin"], //
1011 "Outputs", outputs, //
1012 "PCoefficient", doubles["PCoefficient"], //
1013 "PositiveHysteresis", doubles["PositiveHysteresis"], //
1014 "SetPoint", doubles["SetPoint"], //
1015 "SetPointOffset", setpointOffset, //
1016 "SlewNeg", doubles["SlewNeg"], //
1017 "SlewPos", doubles["SlewPos"], //
1018 "Zones", zones //
1019 ))
James Feist83ff9ab2018-08-31 10:18:24 -07001020 {
James Feist5f2caae2018-12-12 14:08:25 -08001021 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -07001022 }
Myung Baeafc474a2024-10-09 00:53:29 -07001023
James Feist5f2caae2018-12-12 14:08:25 -08001024 if (zones)
James Feist83ff9ab2018-08-31 10:18:24 -07001025 {
James Feist5f2caae2018-12-12 14:08:25 -08001026 std::vector<std::string> zonesStr;
1027 if (!getZonesFromJsonReq(response, *zones, zonesStr))
James Feist83ff9ab2018-08-31 10:18:24 -07001028 {
Ed Tanous62598e32023-07-17 17:06:25 -07001029 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001030 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -07001031 }
James Feistb6baeaa2019-02-21 10:41:40 -08001032 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001033 findChassis(managedObj, zonesStr[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001034 {
Ed Tanous62598e32023-07-17 17:06:25 -07001035 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001036 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001037 response->res,
1038 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001039 return CreatePIDRet::fail;
1040 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001041 output.emplace_back("Zones", std::move(zonesStr));
James Feist5f2caae2018-12-12 14:08:25 -08001042 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001043
1044 if (inputs)
James Feist5f2caae2018-12-12 14:08:25 -08001045 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001046 for (std::string& value : *inputs)
James Feist83ff9ab2018-08-31 10:18:24 -07001047 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001048 std::replace(value.begin(), value.end(), '_', ' ');
James Feist83ff9ab2018-08-31 10:18:24 -07001049 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001050 output.emplace_back("Inputs", *inputs);
1051 }
1052
1053 if (outputs)
1054 {
1055 for (std::string& value : *outputs)
1056 {
1057 std::replace(value.begin(), value.end(), '_', ' ');
1058 }
1059 output.emplace_back("Outputs", *outputs);
James Feist5f2caae2018-12-12 14:08:25 -08001060 }
James Feist83ff9ab2018-08-31 10:18:24 -07001061
James Feistb943aae2019-07-11 16:33:56 -07001062 if (setpointOffset)
1063 {
1064 // translate between redfish and dbus names
1065 if (*setpointOffset == "UpperThresholdNonCritical")
1066 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001067 output.emplace_back("SetPointOffset", "WarningLow");
James Feistb943aae2019-07-11 16:33:56 -07001068 }
1069 else if (*setpointOffset == "LowerThresholdNonCritical")
1070 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001071 output.emplace_back("SetPointOffset", "WarningHigh");
James Feistb943aae2019-07-11 16:33:56 -07001072 }
1073 else if (*setpointOffset == "LowerThresholdCritical")
1074 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001075 output.emplace_back("SetPointOffset", "CriticalLow");
James Feistb943aae2019-07-11 16:33:56 -07001076 }
1077 else if (*setpointOffset == "UpperThresholdCritical")
1078 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001079 output.emplace_back("SetPointOffset", "CriticalHigh");
James Feistb943aae2019-07-11 16:33:56 -07001080 }
1081 else
1082 {
Ed Tanous62598e32023-07-17 17:06:25 -07001083 BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
Ed Tanous9e9b6042024-03-06 14:18:28 -08001084 messages::propertyValueNotInList(response->res, name,
Ed Tanousace85d62021-10-26 12:45:59 -07001085 "SetPointOffset");
James Feistb943aae2019-07-11 16:33:56 -07001086 return CreatePIDRet::fail;
1087 }
1088 }
1089
James Feist5f2caae2018-12-12 14:08:25 -08001090 // doubles
1091 for (const auto& pairs : doubles)
1092 {
1093 if (!pairs.second)
James Feist83ff9ab2018-08-31 10:18:24 -07001094 {
James Feist5f2caae2018-12-12 14:08:25 -08001095 continue;
James Feist83ff9ab2018-08-31 10:18:24 -07001096 }
Ed Tanous62598e32023-07-17 17:06:25 -07001097 BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -08001098 output.emplace_back(pairs.first, *pairs.second);
James Feist83ff9ab2018-08-31 10:18:24 -07001099 }
1100 }
James Feist5f2caae2018-12-12 14:08:25 -08001101
James Feist83ff9ab2018-08-31 10:18:24 -07001102 else if (type == "FanZones")
1103 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001104 output.emplace_back("Type", "Pid.Zone");
James Feist83ff9ab2018-08-31 10:18:24 -07001105
Ed Tanous9e9b6042024-03-06 14:18:28 -08001106 std::optional<std::string> chassisId;
James Feist5f2caae2018-12-12 14:08:25 -08001107 std::optional<double> failSafePercent;
James Feistd3ec07f2019-02-25 14:51:15 -08001108 std::optional<double> minThermalOutput;
Myung Baeafc474a2024-10-09 00:53:29 -07001109 if (!redfish::json_util::readJson( //
1110 jsonValue, response->res, //
1111 "Chassis/@odata.id", chassisId, //
1112 "FailSafePercent", failSafePercent, //
1113 "MinThermalOutput", minThermalOutput))
James Feist83ff9ab2018-08-31 10:18:24 -07001114 {
James Feist5f2caae2018-12-12 14:08:25 -08001115 return CreatePIDRet::fail;
1116 }
James Feist83ff9ab2018-08-31 10:18:24 -07001117
Ed Tanous9e9b6042024-03-06 14:18:28 -08001118 if (chassisId)
James Feist5f2caae2018-12-12 14:08:25 -08001119 {
AppaRao Puli717794d2019-10-18 22:54:53 +05301120 // /redfish/v1/chassis/chassis_name/
Ed Tanous9e9b6042024-03-06 14:18:28 -08001121 if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
James Feist5f2caae2018-12-12 14:08:25 -08001122 {
Ed Tanous9e9b6042024-03-06 14:18:28 -08001123 BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
Ed Tanousace85d62021-10-26 12:45:59 -07001124 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001125 response->res,
Ed Tanous9e9b6042024-03-06 14:18:28 -08001126 boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
James Feist5f2caae2018-12-12 14:08:25 -08001127 return CreatePIDRet::fail;
1128 }
1129 }
James Feistd3ec07f2019-02-25 14:51:15 -08001130 if (minThermalOutput)
James Feist5f2caae2018-12-12 14:08:25 -08001131 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001132 output.emplace_back("MinThermalOutput", *minThermalOutput);
James Feist5f2caae2018-12-12 14:08:25 -08001133 }
1134 if (failSafePercent)
1135 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001136 output.emplace_back("FailSafePercent", *failSafePercent);
James Feist5f2caae2018-12-12 14:08:25 -08001137 }
1138 }
1139 else if (type == "StepwiseControllers")
1140 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001141 output.emplace_back("Type", "Stepwise");
James Feist5f2caae2018-12-12 14:08:25 -08001142
Ed Tanous9e9b6042024-03-06 14:18:28 -08001143 std::optional<std::vector<nlohmann::json::object_t>> zones;
1144 std::optional<std::vector<nlohmann::json::object_t>> steps;
James Feist5f2caae2018-12-12 14:08:25 -08001145 std::optional<std::vector<std::string>> inputs;
1146 std::optional<double> positiveHysteresis;
1147 std::optional<double> negativeHysteresis;
James Feistc33a90e2019-03-01 10:17:44 -08001148 std::optional<std::string> direction; // upper clipping curve vs lower
Myung Baeafc474a2024-10-09 00:53:29 -07001149 if (!redfish::json_util::readJson( //
1150 jsonValue, response->res, //
1151 "Direction", direction, //
1152 "Inputs", inputs, //
1153 "NegativeHysteresis", negativeHysteresis, //
1154 "PositiveHysteresis", positiveHysteresis, //
1155 "Steps", steps, //
1156 "Zones", zones //
1157 ))
James Feist5f2caae2018-12-12 14:08:25 -08001158 {
James Feist5f2caae2018-12-12 14:08:25 -08001159 return CreatePIDRet::fail;
1160 }
1161
1162 if (zones)
1163 {
James Feistb6baeaa2019-02-21 10:41:40 -08001164 std::vector<std::string> zonesStrs;
1165 if (!getZonesFromJsonReq(response, *zones, zonesStrs))
James Feist5f2caae2018-12-12 14:08:25 -08001166 {
Ed Tanous62598e32023-07-17 17:06:25 -07001167 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001168 return CreatePIDRet::fail;
1169 }
James Feistb6baeaa2019-02-21 10:41:40 -08001170 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001171 findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001172 {
Ed Tanous62598e32023-07-17 17:06:25 -07001173 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001174 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001175 response->res,
1176 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001177 return CreatePIDRet::fail;
1178 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001179 output.emplace_back("Zones", std::move(zonesStrs));
James Feist5f2caae2018-12-12 14:08:25 -08001180 }
1181 if (steps)
1182 {
1183 std::vector<double> readings;
1184 std::vector<double> outputs;
1185 for (auto& step : *steps)
1186 {
Ed Tanous543f4402022-01-06 13:12:53 -08001187 double target = 0.0;
1188 double out = 0.0;
James Feist5f2caae2018-12-12 14:08:25 -08001189
Myung Baeafc474a2024-10-09 00:53:29 -07001190 if (!redfish::json_util::readJsonObject( //
1191 step, response->res, //
1192 "Output", out, //
1193 "Target", target //
1194 ))
James Feist5f2caae2018-12-12 14:08:25 -08001195 {
James Feist5f2caae2018-12-12 14:08:25 -08001196 return CreatePIDRet::fail;
1197 }
1198 readings.emplace_back(target);
Ed Tanous23a21a12020-07-25 04:45:05 +00001199 outputs.emplace_back(out);
James Feist5f2caae2018-12-12 14:08:25 -08001200 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001201 output.emplace_back("Reading", std::move(readings));
1202 output.emplace_back("Output", std::move(outputs));
James Feist5f2caae2018-12-12 14:08:25 -08001203 }
1204 if (inputs)
1205 {
1206 for (std::string& value : *inputs)
1207 {
Ed Tanousa170f272022-06-30 21:53:27 -07001208 std::replace(value.begin(), value.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -08001209 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001210 output.emplace_back("Inputs", std::move(*inputs));
James Feist5f2caae2018-12-12 14:08:25 -08001211 }
1212 if (negativeHysteresis)
1213 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001214 output.emplace_back("NegativeHysteresis", *negativeHysteresis);
James Feist5f2caae2018-12-12 14:08:25 -08001215 }
1216 if (positiveHysteresis)
1217 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001218 output.emplace_back("PositiveHysteresis", *positiveHysteresis);
James Feist83ff9ab2018-08-31 10:18:24 -07001219 }
James Feistc33a90e2019-03-01 10:17:44 -08001220 if (direction)
1221 {
1222 constexpr const std::array<const char*, 2> allowedDirections = {
1223 "Ceiling", "Floor"};
Ed Tanous3544d2a2023-08-06 18:12:20 -07001224 if (std::ranges::find(allowedDirections, *direction) ==
1225 allowedDirections.end())
James Feistc33a90e2019-03-01 10:17:44 -08001226 {
1227 messages::propertyValueTypeError(response->res, "Direction",
1228 *direction);
1229 return CreatePIDRet::fail;
1230 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001231 output.emplace_back("Class", *direction);
James Feistc33a90e2019-03-01 10:17:44 -08001232 }
James Feist83ff9ab2018-08-31 10:18:24 -07001233 }
1234 else
1235 {
Ed Tanous62598e32023-07-17 17:06:25 -07001236 BMCWEB_LOG_ERROR("Illegal Type {}", type);
Jason M. Bills35a62c72018-10-09 12:45:45 -07001237 messages::propertyUnknown(response->res, type);
James Feist83ff9ab2018-08-31 10:18:24 -07001238 return CreatePIDRet::fail;
1239 }
1240 return CreatePIDRet::patch;
1241}
James Feist73df0db2019-03-25 15:29:35 -07001242struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
1243{
Ed Tanous6936afe2022-09-08 15:10:39 -07001244 struct CompletionValues
1245 {
1246 std::vector<std::string> supportedProfiles;
1247 std::string currentProfile;
1248 dbus::utility::MapperGetSubTreeResponse subtree;
1249 };
James Feist73df0db2019-03-25 15:29:35 -07001250
Ed Tanous4e23a442022-06-06 09:57:26 -07001251 explicit GetPIDValues(
1252 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +00001253 asyncResp(asyncRespIn)
James Feist73df0db2019-03-25 15:29:35 -07001254
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001255 {}
James Feist73df0db2019-03-25 15:29:35 -07001256
1257 void run()
1258 {
1259 std::shared_ptr<GetPIDValues> self = shared_from_this();
1260
1261 // get all configurations
George Liue99073f2022-12-09 11:06:16 +08001262 constexpr std::array<std::string_view, 4> interfaces = {
1263 pidConfigurationIface, pidZoneConfigurationIface,
1264 objectManagerIface, stepwiseConfigurationIface};
1265 dbus::utility::getSubTree(
1266 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001267 [self](
George Liue99073f2022-12-09 11:06:16 +08001268 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001269 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001270 if (ec)
1271 {
1272 BMCWEB_LOG_ERROR("{}", ec);
1273 messages::internalError(self->asyncResp->res);
1274 return;
1275 }
1276 self->complete.subtree = subtreeLocal;
1277 });
James Feist73df0db2019-03-25 15:29:35 -07001278
1279 // at the same time get the selected profile
George Liue99073f2022-12-09 11:06:16 +08001280 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1281 thermalModeIface};
1282 dbus::utility::getSubTree(
1283 "/", 0, thermalModeIfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001284 [self](
George Liue99073f2022-12-09 11:06:16 +08001285 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001286 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001287 if (ec || subtreeLocal.empty())
James Feist73df0db2019-03-25 15:29:35 -07001288 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001289 return;
1290 }
1291 if (subtreeLocal[0].second.size() != 1)
1292 {
1293 // invalid mapper response, should never happen
1294 BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
James Feist73df0db2019-03-25 15:29:35 -07001295 messages::internalError(self->asyncResp->res);
1296 return;
1297 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001298
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001299 const std::string& path = subtreeLocal[0].first;
1300 const std::string& owner = subtreeLocal[0].second[0].first;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001301
Ed Tanousdeae6a72024-11-11 21:58:57 -08001302 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001303 *crow::connections::systemBus, owner, path,
1304 thermalModeIface,
1305 [path, owner,
1306 self](const boost::system::error_code& ec2,
1307 const dbus::utility::DBusPropertiesMap& resp) {
1308 if (ec2)
1309 {
1310 BMCWEB_LOG_ERROR(
1311 "GetPIDValues: Can't get thermalModeIface {}",
1312 path);
1313 messages::internalError(self->asyncResp->res);
1314 return;
1315 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001316
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001317 const std::string* current = nullptr;
1318 const std::vector<std::string>* supported = nullptr;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001319
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001320 const bool success = sdbusplus::unpackPropertiesNoThrow(
1321 dbus_utils::UnpackErrorPrinter(), resp, "Current",
1322 current, "Supported", supported);
1323
1324 if (!success)
1325 {
1326 messages::internalError(self->asyncResp->res);
1327 return;
1328 }
1329
1330 if (current == nullptr || supported == nullptr)
1331 {
1332 BMCWEB_LOG_ERROR(
1333 "GetPIDValues: thermal mode iface invalid {}",
1334 path);
1335 messages::internalError(self->asyncResp->res);
1336 return;
1337 }
1338 self->complete.currentProfile = *current;
1339 self->complete.supportedProfiles = *supported;
1340 });
George Liue99073f2022-12-09 11:06:16 +08001341 });
James Feist73df0db2019-03-25 15:29:35 -07001342 }
1343
Ed Tanous6936afe2022-09-08 15:10:39 -07001344 static void
1345 processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1346 const CompletionValues& completion)
James Feist73df0db2019-03-25 15:29:35 -07001347 {
1348 if (asyncResp->res.result() != boost::beast::http::status::ok)
1349 {
1350 return;
1351 }
1352 // create map of <connection, path to objMgr>>
Ed Tanous6936afe2022-09-08 15:10:39 -07001353 boost::container::flat_map<
1354 std::string, std::string, std::less<>,
1355 std::vector<std::pair<std::string, std::string>>>
1356 objectMgrPaths;
1357 boost::container::flat_set<std::string, std::less<>,
1358 std::vector<std::string>>
1359 calledConnections;
1360 for (const auto& pathGroup : completion.subtree)
James Feist73df0db2019-03-25 15:29:35 -07001361 {
1362 for (const auto& connectionGroup : pathGroup.second)
1363 {
1364 auto findConnection =
1365 calledConnections.find(connectionGroup.first);
1366 if (findConnection != calledConnections.end())
1367 {
1368 break;
1369 }
1370 for (const std::string& interface : connectionGroup.second)
1371 {
1372 if (interface == objectManagerIface)
1373 {
1374 objectMgrPaths[connectionGroup.first] = pathGroup.first;
1375 }
1376 // this list is alphabetical, so we
1377 // should have found the objMgr by now
1378 if (interface == pidConfigurationIface ||
1379 interface == pidZoneConfigurationIface ||
1380 interface == stepwiseConfigurationIface)
1381 {
1382 auto findObjMgr =
1383 objectMgrPaths.find(connectionGroup.first);
1384 if (findObjMgr == objectMgrPaths.end())
1385 {
Ed Tanous62598e32023-07-17 17:06:25 -07001386 BMCWEB_LOG_DEBUG("{}Has no Object Manager",
1387 connectionGroup.first);
James Feist73df0db2019-03-25 15:29:35 -07001388 continue;
1389 }
1390
1391 calledConnections.insert(connectionGroup.first);
1392
1393 asyncPopulatePid(findObjMgr->first, findObjMgr->second,
Ed Tanous6936afe2022-09-08 15:10:39 -07001394 completion.currentProfile,
1395 completion.supportedProfiles,
James Feist73df0db2019-03-25 15:29:35 -07001396 asyncResp);
1397 break;
1398 }
1399 }
1400 }
1401 }
1402 }
1403
Ed Tanous6936afe2022-09-08 15:10:39 -07001404 ~GetPIDValues()
1405 {
1406 boost::asio::post(crow::connections::systemBus->get_io_context(),
1407 std::bind_front(&processingComplete, asyncResp,
1408 std::move(complete)));
1409 }
1410
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001411 GetPIDValues(const GetPIDValues&) = delete;
1412 GetPIDValues(GetPIDValues&&) = delete;
1413 GetPIDValues& operator=(const GetPIDValues&) = delete;
1414 GetPIDValues& operator=(GetPIDValues&&) = delete;
1415
zhanghch058d1b46d2021-04-01 11:18:24 +08001416 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous6936afe2022-09-08 15:10:39 -07001417 CompletionValues complete;
James Feist73df0db2019-03-25 15:29:35 -07001418};
1419
1420struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
1421{
Ed Tanous9e9b6042024-03-06 14:18:28 -08001422 SetPIDValues(
1423 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1424 std::vector<
1425 std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
1426 configurationsIn,
1427 std::optional<std::string>& profileIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001428 asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
Ed Tanous9e9b6042024-03-06 14:18:28 -08001429 profile(std::move(profileIn))
1430 {}
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001431
1432 SetPIDValues(const SetPIDValues&) = delete;
1433 SetPIDValues(SetPIDValues&&) = delete;
1434 SetPIDValues& operator=(const SetPIDValues&) = delete;
1435 SetPIDValues& operator=(SetPIDValues&&) = delete;
1436
James Feist73df0db2019-03-25 15:29:35 -07001437 void run()
1438 {
1439 if (asyncResp->res.result() != boost::beast::http::status::ok)
1440 {
1441 return;
1442 }
1443
1444 std::shared_ptr<SetPIDValues> self = shared_from_this();
1445
1446 // todo(james): might make sense to do a mapper call here if this
1447 // interface gets more traction
George Liu5eb468d2023-06-20 17:03:24 +08001448 sdbusplus::message::object_path objPath(
1449 "/xyz/openbmc_project/inventory");
1450 dbus::utility::getManagedObjects(
1451 "xyz.openbmc_project.EntityManager", objPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001452 [self](const boost::system::error_code& ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001453 const dbus::utility::ManagedObjectType& mObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001454 if (ec)
James Feiste69d9de2020-02-07 12:23:27 -08001455 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001456 BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
1457 messages::internalError(self->asyncResp->res);
1458 return;
1459 }
1460 const std::array<const char*, 3> configurations = {
1461 pidConfigurationIface, pidZoneConfigurationIface,
1462 stepwiseConfigurationIface};
1463
1464 for (const auto& [path, object] : mObj)
1465 {
1466 for (const auto& [interface, _] : object)
James Feiste69d9de2020-02-07 12:23:27 -08001467 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001468 if (std::ranges::find(configurations, interface) !=
1469 configurations.end())
1470 {
1471 self->objectCount++;
1472 break;
1473 }
James Feiste69d9de2020-02-07 12:23:27 -08001474 }
James Feiste69d9de2020-02-07 12:23:27 -08001475 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001476 self->managedObj = mObj;
1477 });
James Feist73df0db2019-03-25 15:29:35 -07001478
1479 // at the same time get the profile information
George Liue99073f2022-12-09 11:06:16 +08001480 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1481 thermalModeIface};
1482 dbus::utility::getSubTree(
1483 "/", 0, thermalModeIfaces,
1484 [self](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001485 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001486 if (ec || subtree.empty())
James Feist73df0db2019-03-25 15:29:35 -07001487 {
James Feist73df0db2019-03-25 15:29:35 -07001488 return;
1489 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001490 if (subtree[0].second.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001491 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001492 // invalid mapper response, should never happen
1493 BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001494 messages::internalError(self->asyncResp->res);
1495 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001496 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001497
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001498 const std::string& path = subtree[0].first;
1499 const std::string& owner = subtree[0].second[0].first;
Ed Tanousdeae6a72024-11-11 21:58:57 -08001500 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001501 *crow::connections::systemBus, owner, path,
1502 thermalModeIface,
1503 [self, path,
1504 owner](const boost::system::error_code& ec2,
1505 const dbus::utility::DBusPropertiesMap& r) {
1506 if (ec2)
1507 {
1508 BMCWEB_LOG_ERROR(
1509 "SetPIDValues: Can't get thermalModeIface {}",
1510 path);
1511 messages::internalError(self->asyncResp->res);
1512 return;
1513 }
1514 const std::string* current = nullptr;
1515 const std::vector<std::string>* supported = nullptr;
1516
1517 const bool success = sdbusplus::unpackPropertiesNoThrow(
1518 dbus_utils::UnpackErrorPrinter(), r, "Current",
1519 current, "Supported", supported);
1520
1521 if (!success)
1522 {
1523 messages::internalError(self->asyncResp->res);
1524 return;
1525 }
1526
1527 if (current == nullptr || supported == nullptr)
1528 {
1529 BMCWEB_LOG_ERROR(
1530 "SetPIDValues: thermal mode iface invalid {}",
1531 path);
1532 messages::internalError(self->asyncResp->res);
1533 return;
1534 }
1535 self->currentProfile = *current;
1536 self->supportedProfiles = *supported;
1537 self->profileConnection = owner;
1538 self->profilePath = path;
1539 });
George Liue99073f2022-12-09 11:06:16 +08001540 });
James Feist73df0db2019-03-25 15:29:35 -07001541 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001542 void pidSetDone()
James Feist73df0db2019-03-25 15:29:35 -07001543 {
1544 if (asyncResp->res.result() != boost::beast::http::status::ok)
1545 {
1546 return;
1547 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001548 std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
James Feist73df0db2019-03-25 15:29:35 -07001549 if (profile)
1550 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07001551 if (std::ranges::find(supportedProfiles, *profile) ==
1552 supportedProfiles.end())
James Feist73df0db2019-03-25 15:29:35 -07001553 {
1554 messages::actionParameterUnknown(response->res, "Profile",
1555 *profile);
1556 return;
1557 }
1558 currentProfile = *profile;
George Liu9ae226f2023-06-21 17:56:46 +08001559 sdbusplus::asio::setProperty(
1560 *crow::connections::systemBus, profileConnection, profilePath,
1561 thermalModeIface, "Current", *profile,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001562 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001563 if (ec)
1564 {
1565 BMCWEB_LOG_ERROR("Error patching profile{}", ec);
1566 messages::internalError(response->res);
1567 }
1568 });
James Feist73df0db2019-03-25 15:29:35 -07001569 }
1570
1571 for (auto& containerPair : configuration)
1572 {
1573 auto& container = containerPair.second;
1574 if (!container)
1575 {
1576 continue;
1577 }
James Feist6ee7f772020-02-06 16:25:27 -08001578
Ed Tanous02cad962022-06-30 16:50:15 -07001579 const std::string& type = containerPair.first;
James Feist73df0db2019-03-25 15:29:35 -07001580
Ed Tanous9e9b6042024-03-06 14:18:28 -08001581 for (auto& [name, value] : *container)
James Feist73df0db2019-03-25 15:29:35 -07001582 {
Potin Laicddbf3d2023-02-14 14:28:58 +08001583 std::string dbusObjName = name;
1584 std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
Ed Tanous62598e32023-07-17 17:06:25 -07001585 BMCWEB_LOG_DEBUG("looking for {}", name);
James Feist6ee7f772020-02-06 16:25:27 -08001586
Ed Tanous3544d2a2023-08-06 18:12:20 -07001587 auto pathItr = std::ranges::find_if(
1588 managedObj, [&dbusObjName](const auto& obj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001589 return obj.first.filename() == dbusObjName;
1590 });
Ed Tanousb9d36b42022-02-26 21:42:46 -08001591 dbus::utility::DBusPropertiesMap output;
James Feist73df0db2019-03-25 15:29:35 -07001592
1593 output.reserve(16); // The pid interface length
1594
1595 // determines if we're patching entity-manager or
1596 // creating a new object
1597 bool createNewObject = (pathItr == managedObj.end());
Ed Tanous62598e32023-07-17 17:06:25 -07001598 BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
James Feist6ee7f772020-02-06 16:25:27 -08001599
James Feist73df0db2019-03-25 15:29:35 -07001600 std::string iface;
Ed Tanousea2b6702022-03-07 16:48:38 -08001601 if (!createNewObject)
James Feist73df0db2019-03-25 15:29:35 -07001602 {
Potin Lai8be2b5b2022-11-22 13:27:16 +08001603 bool findInterface = false;
Ed Tanousea2b6702022-03-07 16:48:38 -08001604 for (const auto& interface : pathItr->second)
James Feist73df0db2019-03-25 15:29:35 -07001605 {
Ed Tanousea2b6702022-03-07 16:48:38 -08001606 if (interface.first == pidConfigurationIface)
1607 {
1608 if (type == "PidControllers" ||
1609 type == "FanControllers")
1610 {
1611 iface = pidConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001612 findInterface = true;
1613 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001614 }
1615 }
1616 else if (interface.first == pidZoneConfigurationIface)
1617 {
1618 if (type == "FanZones")
1619 {
PavanKumarIntelda393502024-03-15 05:47:02 +00001620 iface = pidZoneConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001621 findInterface = true;
1622 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001623 }
1624 }
1625 else if (interface.first == stepwiseConfigurationIface)
1626 {
1627 if (type == "StepwiseControllers")
1628 {
1629 iface = stepwiseConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001630 findInterface = true;
1631 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001632 }
1633 }
James Feist73df0db2019-03-25 15:29:35 -07001634 }
Potin Lai8be2b5b2022-11-22 13:27:16 +08001635
1636 // create new object if interface not found
1637 if (!findInterface)
1638 {
1639 createNewObject = true;
1640 }
James Feist73df0db2019-03-25 15:29:35 -07001641 }
James Feist6ee7f772020-02-06 16:25:27 -08001642
Ed Tanous9e9b6042024-03-06 14:18:28 -08001643 if (createNewObject && value == nullptr)
James Feist6ee7f772020-02-06 16:25:27 -08001644 {
Gunnar Mills4e0453b2020-07-08 14:00:30 -05001645 // can't delete a non-existent object
Ed Tanous9e9b6042024-03-06 14:18:28 -08001646 messages::propertyValueNotInList(response->res, value,
Ed Tanouse2616cc2022-06-27 12:45:55 -07001647 name);
James Feist6ee7f772020-02-06 16:25:27 -08001648 continue;
1649 }
1650
1651 std::string path;
1652 if (pathItr != managedObj.end())
1653 {
1654 path = pathItr->first.str;
1655 }
1656
Ed Tanous62598e32023-07-17 17:06:25 -07001657 BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
James Feiste69d9de2020-02-07 12:23:27 -08001658
1659 // arbitrary limit to avoid attacks
1660 constexpr const size_t controllerLimit = 500;
James Feist14b0b8d2020-02-12 11:52:07 -08001661 if (createNewObject && objectCount >= controllerLimit)
James Feiste69d9de2020-02-07 12:23:27 -08001662 {
1663 messages::resourceExhaustion(response->res, type);
1664 continue;
1665 }
Ed Tanousa170f272022-06-30 21:53:27 -07001666 std::string escaped = name;
1667 std::replace(escaped.begin(), escaped.end(), '_', ' ');
1668 output.emplace_back("Name", escaped);
James Feist73df0db2019-03-25 15:29:35 -07001669
1670 std::string chassis;
1671 CreatePIDRet ret = createPidInterface(
Ed Tanous9e9b6042024-03-06 14:18:28 -08001672 response, type, name, value, path, managedObj,
1673 createNewObject, output, chassis, currentProfile);
James Feist73df0db2019-03-25 15:29:35 -07001674 if (ret == CreatePIDRet::fail)
1675 {
1676 return;
1677 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001678 if (ret == CreatePIDRet::del)
James Feist73df0db2019-03-25 15:29:35 -07001679 {
1680 continue;
1681 }
1682
1683 if (!createNewObject)
1684 {
1685 for (const auto& property : output)
1686 {
Potin Lai7a696972023-11-09 12:18:20 +08001687 crow::connections::systemBus->async_method_call(
James Feist73df0db2019-03-25 15:29:35 -07001688 [response,
1689 propertyName{std::string(property.first)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001690 const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001691 if (ec)
1692 {
1693 BMCWEB_LOG_ERROR("Error patching {}: {}",
1694 propertyName, ec);
1695 messages::internalError(response->res);
1696 return;
1697 }
1698 messages::success(response->res);
1699 },
Potin Lai7a696972023-11-09 12:18:20 +08001700 "xyz.openbmc_project.EntityManager", path,
1701 "org.freedesktop.DBus.Properties", "Set", iface,
1702 property.first, property.second);
James Feist73df0db2019-03-25 15:29:35 -07001703 }
1704 }
1705 else
1706 {
1707 if (chassis.empty())
1708 {
Ed Tanous62598e32023-07-17 17:06:25 -07001709 BMCWEB_LOG_ERROR("Failed to get chassis from config");
Ed Tanousace85d62021-10-26 12:45:59 -07001710 messages::internalError(response->res);
James Feist73df0db2019-03-25 15:29:35 -07001711 return;
1712 }
1713
1714 bool foundChassis = false;
1715 for (const auto& obj : managedObj)
1716 {
Ed Tanous91f75ca2024-06-10 13:56:43 -07001717 if (obj.first.filename() == chassis)
James Feist73df0db2019-03-25 15:29:35 -07001718 {
1719 chassis = obj.first.str;
1720 foundChassis = true;
1721 break;
1722 }
1723 }
1724 if (!foundChassis)
1725 {
Ed Tanous62598e32023-07-17 17:06:25 -07001726 BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
James Feist73df0db2019-03-25 15:29:35 -07001727 messages::resourceMissingAtURI(
Ed Tanousace85d62021-10-26 12:45:59 -07001728 response->res,
Ed Tanousef4c65b2023-04-24 15:28:50 -07001729 boost::urls::format("/redfish/v1/Chassis/{}",
1730 chassis));
James Feist73df0db2019-03-25 15:29:35 -07001731 return;
1732 }
1733
1734 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001735 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001736 if (ec)
1737 {
1738 BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
1739 ec);
1740 messages::internalError(response->res);
1741 return;
1742 }
1743 messages::success(response->res);
1744 },
James Feist73df0db2019-03-25 15:29:35 -07001745 "xyz.openbmc_project.EntityManager", chassis,
1746 "xyz.openbmc_project.AddObject", "AddObject", output);
1747 }
1748 }
1749 }
1750 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001751
1752 ~SetPIDValues()
1753 {
1754 try
1755 {
1756 pidSetDone();
1757 }
1758 catch (...)
1759 {
Ed Tanous62598e32023-07-17 17:06:25 -07001760 BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -08001761 }
1762 }
1763
zhanghch058d1b46d2021-04-01 11:18:24 +08001764 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous9e9b6042024-03-06 14:18:28 -08001765 std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
James Feist73df0db2019-03-25 15:29:35 -07001766 configuration;
1767 std::optional<std::string> profile;
1768 dbus::utility::ManagedObjectType managedObj;
1769 std::vector<std::string> supportedProfiles;
1770 std::string currentProfile;
1771 std::string profileConnection;
1772 std::string profilePath;
James Feist14b0b8d2020-02-12 11:52:07 -08001773 size_t objectCount = 0;
James Feist73df0db2019-03-25 15:29:35 -07001774};
James Feist83ff9ab2018-08-31 10:18:24 -07001775
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001776/**
1777 * @brief Retrieves BMC manager location data over DBus
1778 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001779 * @param[in] asyncResp Shared pointer for completing asynchronous calls
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001780 * @param[in] connectionName - service name
1781 * @param[in] path - object path
1782 * @return none
1783 */
Ed Tanousac106bf2023-06-07 09:24:59 -07001784inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001785 const std::string& connectionName,
1786 const std::string& path)
1787{
Ed Tanous62598e32023-07-17 17:06:25 -07001788 BMCWEB_LOG_DEBUG("Get BMC manager Location data.");
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001789
Ed Tanousdeae6a72024-11-11 21:58:57 -08001790 dbus::utility::getProperty<std::string>(
1791 connectionName, path,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001792 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanousac106bf2023-06-07 09:24:59 -07001793 [asyncResp](const boost::system::error_code& ec,
1794 const std::string& property) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001795 if (ec)
1796 {
1797 BMCWEB_LOG_DEBUG("DBUS response error for "
1798 "Location");
1799 messages::internalError(asyncResp->res);
1800 return;
1801 }
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001802
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001803 asyncResp->res
1804 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
1805 property;
1806 });
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001807}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001808// avoid name collision systems.hpp
1809inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001810 managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811{
Ed Tanous62598e32023-07-17 17:06:25 -07001812 BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time");
Ed Tanous52cc1122020-07-18 13:51:21 -07001813
Ed Tanousdeae6a72024-11-11 21:58:57 -08001814 dbus::utility::getProperty<uint64_t>(
1815 "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
1816 "xyz.openbmc_project.State.BMC", "LastRebootTime",
Ed Tanousac106bf2023-06-07 09:24:59 -07001817 [asyncResp](const boost::system::error_code& ec,
1818 const uint64_t lastResetTime) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001819 if (ec)
1820 {
1821 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1822 return;
1823 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001824
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001825 // LastRebootTime is epoch time, in milliseconds
1826 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
1827 uint64_t lastResetTimeStamp = lastResetTime / 1000;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001828
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001829 // Convert to ISO 8601 standard
1830 asyncResp->res.jsonValue["LastResetTime"] =
1831 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1832 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001833}
1834
1835/**
1836 * @brief Set the running firmware image
1837 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001838 * @param[i,o] asyncResp - Async response object
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001839 * @param[i] runningFirmwareTarget - Image to make the running image
1840 *
1841 * @return void
1842 */
1843inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001844 setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001845 const std::string& runningFirmwareTarget)
1846{
1847 // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1848 std::string::size_type idPos = runningFirmwareTarget.rfind('/');
1849 if (idPos == std::string::npos)
1850 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001851 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001852 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001853 BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001854 return;
1855 }
1856 idPos++;
1857 if (idPos >= runningFirmwareTarget.size())
1858 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001859 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001860 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001861 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001862 return;
1863 }
1864 std::string firmwareId = runningFirmwareTarget.substr(idPos);
1865
1866 // Make sure the image is valid before setting priority
George Liu5eb468d2023-06-20 17:03:24 +08001867 sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
1868 dbus::utility::getManagedObjects(
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -07001869 getBMCUpdateServiceName(), objPath,
George Liu5eb468d2023-06-20 17:03:24 +08001870 [asyncResp, firmwareId, runningFirmwareTarget](
1871 const boost::system::error_code& ec,
1872 const dbus::utility::ManagedObjectType& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001873 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001874 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001875 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
Ed Tanousac106bf2023-06-07 09:24:59 -07001876 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001877 return;
1878 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001879
1880 if (subtree.empty())
1881 {
1882 BMCWEB_LOG_DEBUG("Can't find image!");
1883 messages::internalError(asyncResp->res);
1884 return;
1885 }
1886
1887 bool foundImage = false;
1888 for (const auto& object : subtree)
1889 {
1890 const std::string& path =
1891 static_cast<const std::string&>(object.first);
1892 std::size_t idPos2 = path.rfind('/');
1893
1894 if (idPos2 == std::string::npos)
1895 {
1896 continue;
1897 }
1898
1899 idPos2++;
1900 if (idPos2 >= path.size())
1901 {
1902 continue;
1903 }
1904
1905 if (path.substr(idPos2) == firmwareId)
1906 {
1907 foundImage = true;
1908 break;
1909 }
1910 }
1911
1912 if (!foundImage)
1913 {
1914 messages::propertyValueNotInList(
1915 asyncResp->res, runningFirmwareTarget, "@odata.id");
1916 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
1917 return;
1918 }
1919
1920 BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
1921 firmwareId);
1922
1923 // Only support Immediate
1924 // An addition could be a Redfish Setting like
1925 // ActiveSoftwareImageApplyTime and support OnReset
1926 sdbusplus::asio::setProperty(
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -07001927 *crow::connections::systemBus, getBMCUpdateServiceName(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001928 "/xyz/openbmc_project/software/" + firmwareId,
1929 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
1930 static_cast<uint8_t>(0),
1931 [asyncResp](const boost::system::error_code& ec2) {
1932 if (ec2)
1933 {
1934 BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1935 messages::internalError(asyncResp->res);
1936 return;
1937 }
1938 doBMCGracefulRestart(asyncResp);
1939 });
George Liu5eb468d2023-06-20 17:03:24 +08001940 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001941}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001943inline void afterSetDateTime(
1944 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1945 const boost::system::error_code& ec, const sdbusplus::message_t& msg)
Ed Tanousc51afd52024-03-07 10:13:14 -08001946{
1947 if (ec)
1948 {
1949 BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1950 ec);
1951 const sd_bus_error* dbusError = msg.get_error();
1952 if (dbusError != nullptr)
1953 {
1954 std::string_view errorName(dbusError->name);
1955 if (errorName ==
1956 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1957 {
1958 BMCWEB_LOG_DEBUG("Setting conflict");
1959 messages::propertyValueConflict(
1960 asyncResp->res, "DateTime",
1961 "Managers/NetworkProtocol/NTPProcotolEnabled");
1962 return;
1963 }
1964 }
1965 messages::internalError(asyncResp->res);
1966 return;
1967 }
1968 asyncResp->res.result(boost::beast::http::status::no_content);
1969}
1970
1971inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1972 const std::string& datetime)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001973{
Ed Tanous62598e32023-07-17 17:06:25 -07001974 BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001975
Ed Tanousc2e32002023-01-07 22:05:08 -08001976 std::optional<redfish::time_utils::usSinceEpoch> us =
1977 redfish::time_utils::dateStringToEpoch(datetime);
1978 if (!us)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001979 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001980 messages::propertyValueFormatError(asyncResp->res, datetime,
1981 "DateTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001982 return;
1983 }
Ed Tanousc51afd52024-03-07 10:13:14 -08001984 // Set the absolute datetime
1985 bool relative = false;
1986 bool interactive = false;
1987 crow::connections::systemBus->async_method_call(
1988 [asyncResp](const boost::system::error_code& ec,
1989 const sdbusplus::message_t& msg) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001990 afterSetDateTime(asyncResp, ec, msg);
1991 },
Ed Tanousc51afd52024-03-07 10:13:14 -08001992 "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1993 "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1994 interactive);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001995}
1996
Ed Tanous75815e52022-10-05 17:21:13 -07001997inline void
1998 checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1999{
Ed Tanousdeae6a72024-11-11 21:58:57 -08002000 dbus::utility::getProperty<std::string>(
2001 "org.freedesktop.systemd1",
Ed Tanous75815e52022-10-05 17:21:13 -07002002 "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
2003 "org.freedesktop.systemd1.Unit", "ActiveState",
2004 [asyncResp](const boost::system::error_code& ec,
2005 const std::string& val) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002006 if (!ec)
Ed Tanous75815e52022-10-05 17:21:13 -07002007 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002008 if (val == "active")
2009 {
2010 asyncResp->res.jsonValue["Status"]["Health"] =
2011 resource::Health::Critical;
2012 asyncResp->res.jsonValue["Status"]["State"] =
2013 resource::State::Quiesced;
2014 return;
2015 }
Ed Tanous75815e52022-10-05 17:21:13 -07002016 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002017 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
2018 asyncResp->res.jsonValue["Status"]["State"] =
2019 resource::State::Enabled;
2020 });
Ed Tanous75815e52022-10-05 17:21:13 -07002021}
2022
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002023inline void requestRoutesManager(App& app)
2024{
2025 std::string uuid = persistent_data::getConfig().systemUuid;
2026
Ed Tanous253f11b2024-05-16 09:38:31 -07002027 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002028 .privileges(redfish::privileges::getManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002029 .methods(
2030 boost::beast::http::verb::
2031 get)([&app,
2032 uuid](const crow::Request& req,
2033 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2034 const std::string& managerId) {
2035 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2036 {
2037 return;
2038 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002039
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002040 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2041 {
2042 messages::resourceNotFound(asyncResp->res, "Manager",
2043 managerId);
2044 return;
2045 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002046
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002047 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2048 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2049 asyncResp->res.jsonValue["@odata.type"] =
2050 "#Manager.v1_14_0.Manager";
2051 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
2052 asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
2053 asyncResp->res.jsonValue["Description"] =
2054 "Baseboard Management Controller";
2055 asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
Ed Tanous14766872022-03-15 10:44:42 -07002056
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002057 asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
2058 asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
2059 asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2060 asyncResp->res.jsonValue["Model"] =
2061 "OpenBmc"; // TODO(ed), get model
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002062
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002063 asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2064 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
Ed Tanous253f11b2024-05-16 09:38:31 -07002065 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002066 asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2067 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2068 BMCWEB_REDFISH_MANAGER_URI_NAME);
2069 asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2070 boost::urls::format(
2071 "/redfish/v1/Managers/{}/EthernetInterfaces",
2072 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002073
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002074 if constexpr (BMCWEB_VM_NBDPROXY)
Ed Tanous75815e52022-10-05 17:21:13 -07002075 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002076 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2077 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2078 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002079 }
2080
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002081 // default oem data
2082 nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
2083 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2084 oem["@odata.id"] =
2085 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2086 BMCWEB_REDFISH_MANAGER_URI_NAME);
2087 oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2088 oemOpenbmc["@odata.id"] =
2089 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2090 BMCWEB_REDFISH_MANAGER_URI_NAME);
2091
2092 nlohmann::json::object_t certificates;
2093 certificates["@odata.id"] = boost::urls::format(
2094 "/redfish/v1/Managers/{}/Truststore/Certificates",
2095 BMCWEB_REDFISH_MANAGER_URI_NAME);
2096 oemOpenbmc["Certificates"] = std::move(certificates);
2097
2098 // Manager.Reset (an action) can be many values, OpenBMC only
2099 // supports BMC reboot.
2100 nlohmann::json& managerReset =
2101 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2102 managerReset["target"] = boost::urls::format(
2103 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2104 BMCWEB_REDFISH_MANAGER_URI_NAME);
2105 managerReset["@Redfish.ActionInfo"] =
2106 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2107 BMCWEB_REDFISH_MANAGER_URI_NAME);
2108
2109 // ResetToDefaults (Factory Reset) has values like
2110 // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
2111 // on OpenBMC
2112 nlohmann::json& resetToDefaults =
2113 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2114 resetToDefaults["target"] = boost::urls::format(
2115 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2116 BMCWEB_REDFISH_MANAGER_URI_NAME);
2117 resetToDefaults["ResetType@Redfish.AllowableValues"] =
2118 nlohmann::json::array_t({"ResetAll"});
2119
2120 std::pair<std::string, std::string> redfishDateTimeOffset =
2121 redfish::time_utils::getDateTimeOffsetNow();
2122
2123 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2124 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2125 redfishDateTimeOffset.second;
2126
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002127 if constexpr (BMCWEB_KVM)
Ed Tanous002d39b2022-05-31 08:59:27 -07002128 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002129 // Fill in GraphicalConsole info
2130 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
2131 true;
2132 asyncResp->res
2133 .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
2134 asyncResp->res
2135 .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2136 nlohmann::json::array_t({"KVMIP"});
2137 }
2138 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2139 {
2140 asyncResp->res
2141 .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
2142
2143 nlohmann::json::array_t managerForServers;
2144 nlohmann::json::object_t manager;
2145 manager["@odata.id"] = std::format(
2146 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2147 managerForServers.emplace_back(std::move(manager));
2148
2149 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
2150 std::move(managerForServers);
Ed Tanous002d39b2022-05-31 08:59:27 -07002151 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002152
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002153 sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
2154 "FirmwareVersion", true);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002155
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002156 managerGetLastResetTime(asyncResp);
2157
2158 // ManagerDiagnosticData is added for all BMCs.
2159 nlohmann::json& managerDiagnosticData =
2160 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2161 managerDiagnosticData["@odata.id"] = boost::urls::format(
2162 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2163 BMCWEB_REDFISH_MANAGER_URI_NAME);
2164
2165 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
Ed Tanous002d39b2022-05-31 08:59:27 -07002166 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002167 auto pids = std::make_shared<GetPIDValues>(asyncResp);
2168 pids->run();
2169 }
2170
2171 getMainChassisId(asyncResp, [](const std::string& chassisId,
2172 const std::shared_ptr<
2173 bmcweb::AsyncResp>& aRsp) {
2174 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2175 1;
2176 nlohmann::json::array_t managerForChassis;
2177 nlohmann::json::object_t managerObj;
2178 boost::urls::url chassiUrl =
2179 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2180 managerObj["@odata.id"] = chassiUrl;
2181 managerForChassis.emplace_back(std::move(managerObj));
2182 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
2183 std::move(managerForChassis);
2184 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2185 chassiUrl;
2186 });
2187
Ed Tanousdeae6a72024-11-11 21:58:57 -08002188 dbus::utility::getProperty<double>(
2189 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
2190 "org.freedesktop.systemd1.Manager", "Progress",
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002191 [asyncResp](const boost::system::error_code& ec, double val) {
2192 if (ec)
2193 {
2194 BMCWEB_LOG_ERROR("Error while getting progress");
2195 messages::internalError(asyncResp->res);
2196 return;
2197 }
2198 if (val < 1.0)
2199 {
2200 asyncResp->res.jsonValue["Status"]["Health"] =
2201 resource::Health::OK;
2202 asyncResp->res.jsonValue["Status"]["State"] =
2203 resource::State::Starting;
2204 return;
2205 }
2206 checkForQuiesced(asyncResp);
2207 });
2208
2209 constexpr std::array<std::string_view, 1> interfaces = {
2210 "xyz.openbmc_project.Inventory.Item.Bmc"};
2211 dbus::utility::getSubTree(
2212 "/xyz/openbmc_project/inventory", 0, interfaces,
2213 [asyncResp](
2214 const boost::system::error_code& ec,
2215 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2216 if (ec)
2217 {
2218 BMCWEB_LOG_DEBUG(
2219 "D-Bus response error on GetSubTree {}", ec);
2220 return;
2221 }
2222 if (subtree.empty())
2223 {
2224 BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
2225 return;
2226 }
2227 // Assume only 1 bmc D-Bus object
2228 // Throw an error if there is more than 1
2229 if (subtree.size() > 1)
2230 {
2231 BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
2232 messages::internalError(asyncResp->res);
2233 return;
2234 }
2235
2236 if (subtree[0].first.empty() ||
2237 subtree[0].second.size() != 1)
2238 {
2239 BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
2240 messages::internalError(asyncResp->res);
2241 return;
2242 }
2243
2244 const std::string& path = subtree[0].first;
2245 const std::string& connectionName =
2246 subtree[0].second[0].first;
2247
2248 for (const auto& interfaceName :
2249 subtree[0].second[0].second)
2250 {
2251 if (interfaceName ==
2252 "xyz.openbmc_project.Inventory.Decorator.Asset")
2253 {
Ed Tanousdeae6a72024-11-11 21:58:57 -08002254 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002255 *crow::connections::systemBus, connectionName,
2256 path,
2257 "xyz.openbmc_project.Inventory.Decorator.Asset",
2258 [asyncResp](
2259 const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002260 const dbus::utility::DBusPropertiesMap&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002261 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002262 if (ec2)
2263 {
2264 BMCWEB_LOG_DEBUG(
2265 "Can't get bmc asset!");
2266 return;
2267 }
2268
2269 const std::string* partNumber = nullptr;
2270 const std::string* serialNumber = nullptr;
2271 const std::string* manufacturer = nullptr;
2272 const std::string* model = nullptr;
2273 const std::string* sparePartNumber =
2274 nullptr;
2275
2276 const bool success =
2277 sdbusplus::unpackPropertiesNoThrow(
2278 dbus_utils::UnpackErrorPrinter(),
2279 propertiesList, "PartNumber",
2280 partNumber, "SerialNumber",
2281 serialNumber, "Manufacturer",
2282 manufacturer, "Model", model,
2283 "SparePartNumber", sparePartNumber);
2284
2285 if (!success)
2286 {
2287 messages::internalError(asyncResp->res);
2288 return;
2289 }
2290
2291 if (partNumber != nullptr)
2292 {
2293 asyncResp->res.jsonValue["PartNumber"] =
2294 *partNumber;
2295 }
2296
2297 if (serialNumber != nullptr)
2298 {
2299 asyncResp->res
2300 .jsonValue["SerialNumber"] =
2301 *serialNumber;
2302 }
2303
2304 if (manufacturer != nullptr)
2305 {
2306 asyncResp->res
2307 .jsonValue["Manufacturer"] =
2308 *manufacturer;
2309 }
2310
2311 if (model != nullptr)
2312 {
2313 asyncResp->res.jsonValue["Model"] =
2314 *model;
2315 }
2316
2317 if (sparePartNumber != nullptr)
2318 {
2319 asyncResp->res
2320 .jsonValue["SparePartNumber"] =
2321 *sparePartNumber;
2322 }
2323 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002324 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002325 else if (
2326 interfaceName ==
2327 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02002328 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002329 getLocation(asyncResp, connectionName, path);
Ed Tanous002d39b2022-05-31 08:59:27 -07002330 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002331 }
2332 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002333 });
2334
Ed Tanous253f11b2024-05-16 09:38:31 -07002335 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002336 .privileges(redfish::privileges::patchManager)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002337 .methods(boost::beast::http::verb::patch)(
2338 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002339 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2340 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002341 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2342 {
2343 return;
2344 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002345
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002346 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2347 {
2348 messages::resourceNotFound(asyncResp->res, "Manager",
2349 managerId);
2350 return;
2351 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002352
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002353 std::optional<std::string> activeSoftwareImageOdataId;
2354 std::optional<std::string> datetime;
2355 std::optional<nlohmann::json::object_t> pidControllers;
2356 std::optional<nlohmann::json::object_t> fanControllers;
2357 std::optional<nlohmann::json::object_t> fanZones;
2358 std::optional<nlohmann::json::object_t> stepwiseControllers;
2359 std::optional<std::string> profile;
Ed Tanous002d39b2022-05-31 08:59:27 -07002360
Myung Baeafc474a2024-10-09 00:53:29 -07002361 if (!json_util::readJsonPatch( //
2362 req, asyncResp->res, //
2363 "DateTime", datetime, //
2364 "Links/ActiveSoftwareImage/@odata.id",
2365 activeSoftwareImageOdataId, //
2366 "Oem/OpenBmc/Fan/FanControllers", fanControllers, //
2367 "Oem/OpenBmc/Fan/FanZones", fanZones, //
2368 "Oem/OpenBmc/Fan/PidControllers", pidControllers, //
2369 "Oem/OpenBmc/Fan/Profile", profile, //
2370 "Oem/OpenBmc/Fan/StepwiseControllers",
2371 stepwiseControllers //
2372 ))
2373 {
2374 return;
2375 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002376
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002377 if (pidControllers || fanControllers || fanZones ||
2378 stepwiseControllers || profile)
2379 {
2380 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
2381 {
2382 std::vector<
2383 std::pair<std::string,
Ed Tanous25b54db2024-04-17 15:40:31 -07002384 std::optional<nlohmann::json::object_t>>>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002385 configuration;
2386 if (pidControllers)
2387 {
2388 configuration.emplace_back(
2389 "PidControllers", std::move(pidControllers));
2390 }
2391 if (fanControllers)
2392 {
2393 configuration.emplace_back(
2394 "FanControllers", std::move(fanControllers));
2395 }
2396 if (fanZones)
2397 {
2398 configuration.emplace_back("FanZones",
2399 std::move(fanZones));
2400 }
2401 if (stepwiseControllers)
2402 {
2403 configuration.emplace_back(
2404 "StepwiseControllers",
2405 std::move(stepwiseControllers));
2406 }
2407 auto pid = std::make_shared<SetPIDValues>(
2408 asyncResp, std::move(configuration), profile);
2409 pid->run();
2410 }
2411 else
2412 {
2413 messages::propertyUnknown(asyncResp->res, "Oem");
2414 return;
2415 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002416 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002417
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002418 if (activeSoftwareImageOdataId)
2419 {
2420 setActiveFirmwareImage(asyncResp,
2421 *activeSoftwareImageOdataId);
2422 }
Ed Tanous9e9b6042024-03-06 14:18:28 -08002423
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002424 if (datetime)
2425 {
2426 setDateTime(asyncResp, *datetime);
2427 }
2428 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002429}
2430
2431inline void requestRoutesManagerCollection(App& app)
2432{
2433 BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
Ed Tanoused398212021-06-09 17:05:54 -07002434 .privileges(redfish::privileges::getManagerCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002435 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002436 [&app](const crow::Request& req,
2437 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002438 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2439 {
2440 return;
2441 }
2442 // Collections don't include the static data added by SubRoute
2443 // because it has a duplicate entry for members
2444 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
2445 asyncResp->res.jsonValue["@odata.type"] =
2446 "#ManagerCollection.ManagerCollection";
2447 asyncResp->res.jsonValue["Name"] = "Manager Collection";
2448 asyncResp->res.jsonValue["Members@odata.count"] = 1;
2449 nlohmann::json::array_t members;
2450 nlohmann::json& bmc = members.emplace_back();
2451 bmc["@odata.id"] = boost::urls::format(
2452 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2453 asyncResp->res.jsonValue["Members"] = std::move(members);
2454 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002455}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002456} // namespace redfish