blob: 82ee25fb9d1dce13b1c6ee1f61ba487e7ba960fd [file] [log] [blame]
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2018 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
Borawski.Lukasz9c3106852018-02-09 15:24:22 +010015*/
16#pragma once
17
Willy Tu13451e32023-05-24 16:08:18 -070018#include "bmcweb_config.h"
19
Sui Chena51fc2d2022-07-14 17:21:53 -070020#include "app.hpp"
21#include "dbus_utility.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070022#include "generated/enums/action_info.hpp"
23#include "generated/enums/manager.hpp"
24#include "generated/enums/resource.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070025#include "query.hpp"
Jennifer Leec5d03ff2019-03-08 15:42:58 -080026#include "redfish_util.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070027#include "registries/privilege_registry.hpp"
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +020028#include "utils/dbus_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080029#include "utils/json_utils.hpp"
Sui Chena51fc2d2022-07-14 17:21:53 -070030#include "utils/sw_utils.hpp"
31#include "utils/systemd_utils.hpp"
Ed Tanous2b829372022-08-03 14:22:34 -070032#include "utils/time_utils.hpp"
Borawski.Lukasz9c3106852018-02-09 15:24:22 +010033
George Liue99073f2022-12-09 11:06:16 +080034#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070035#include <boost/url/format.hpp>
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +020036#include <sdbusplus/asio/property.hpp>
37#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038
Ed Tanousa170f272022-06-30 21:53:27 -070039#include <algorithm>
George Liue99073f2022-12-09 11:06:16 +080040#include <array>
Gunnar Mills4bfefa72020-07-30 13:54:29 -050041#include <cstdint>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042#include <memory>
Konstantin Aladyshev9970e932024-02-20 09:51:29 +030043#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070044#include <ranges>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045#include <sstream>
Konstantin Aladyshev9970e932024-02-20 09:51:29 +030046#include <string>
George Liue99073f2022-12-09 11:06:16 +080047#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080048#include <variant>
James Feist5b4aa862018-08-16 14:07:01 -070049
Ed Tanous1abe55e2018-09-05 08:30:59 -070050namespace redfish
51{
Jennifer Leeed5befb2018-08-10 11:29:45 -070052
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -070053inline std::string getBMCUpdateServiceName()
54{
55 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
56 {
57 return "xyz.openbmc_project.Software.Manager";
58 }
59 return "xyz.openbmc_project.Software.BMC.Updater";
60}
61
62inline std::string getBMCUpdateServicePath()
63{
64 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
65 {
66 return "/xyz/openbmc_project/software/bmc";
67 }
68 return "/xyz/openbmc_project/software";
69}
70
Jennifer Leeed5befb2018-08-10 11:29:45 -070071/**
Gunnar Mills2a5c4402020-05-19 09:07:24 -050072 * Function reboots the BMC.
73 *
74 * @param[in] asyncResp - Shared pointer for completing asynchronous calls
Jennifer Leeed5befb2018-08-10 11:29:45 -070075 */
zhanghch058d1b46d2021-04-01 11:18:24 +080076inline void
77 doBMCGracefulRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Gunnar Mills2a5c4402020-05-19 09:07:24 -050078{
79 const char* processName = "xyz.openbmc_project.State.BMC";
80 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
81 const char* interfaceName = "xyz.openbmc_project.State.BMC";
82 const std::string& propertyValue =
83 "xyz.openbmc_project.State.BMC.Transition.Reboot";
84 const char* destProperty = "RequestedBMCTransition";
85
86 // Create the D-Bus variant for D-Bus call.
George Liu9ae226f2023-06-21 17:56:46 +080087 sdbusplus::asio::setProperty(
88 *crow::connections::systemBus, processName, objectPath, interfaceName,
89 destProperty, propertyValue,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080090 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040091 // Use "Set" method to set the property value.
92 if (ec)
93 {
94 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
95 messages::internalError(asyncResp->res);
96 return;
97 }
Gunnar Mills2a5c4402020-05-19 09:07:24 -050098
Patrick Williamsbd79bce2024-08-16 15:22:20 -040099 messages::success(asyncResp->res);
100 });
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500101}
102
zhanghch058d1b46d2021-04-01 11:18:24 +0800103inline void
104 doBMCForceRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000105{
106 const char* processName = "xyz.openbmc_project.State.BMC";
107 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
108 const char* interfaceName = "xyz.openbmc_project.State.BMC";
109 const std::string& propertyValue =
110 "xyz.openbmc_project.State.BMC.Transition.HardReboot";
111 const char* destProperty = "RequestedBMCTransition";
112
113 // Create the D-Bus variant for D-Bus call.
George Liu9ae226f2023-06-21 17:56:46 +0800114 sdbusplus::asio::setProperty(
115 *crow::connections::systemBus, processName, objectPath, interfaceName,
116 destProperty, propertyValue,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800117 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400118 // Use "Set" method to set the property value.
119 if (ec)
120 {
121 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
122 messages::internalError(asyncResp->res);
123 return;
124 }
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000125
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400126 messages::success(asyncResp->res);
127 });
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000128}
129
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500130/**
131 * ManagerResetAction class supports the POST method for the Reset (reboot)
132 * action.
133 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700134inline void requestRoutesManagerResetAction(App& app)
Jennifer Leeed5befb2018-08-10 11:29:45 -0700135{
Jennifer Leeed5befb2018-08-10 11:29:45 -0700136 /**
Jennifer Leeed5befb2018-08-10 11:29:45 -0700137 * Function handles POST method request.
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500138 * Analyzes POST body before sending Reset (Reboot) request data to D-Bus.
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000139 * OpenBMC supports ResetType "GracefulRestart" and "ForceRestart".
Jennifer Leeed5befb2018-08-10 11:29:45 -0700140 */
Jennifer Leeed5befb2018-08-10 11:29:45 -0700141
Ed Tanous253f11b2024-05-16 09:38:31 -0700142 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Actions/Manager.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700143 .privileges(redfish::privileges::postManager)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700144 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700145 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700146 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
147 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400148 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
149 {
150 return;
151 }
152 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
153 {
154 messages::resourceNotFound(asyncResp->res, "Manager",
155 managerId);
156 return;
157 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700158
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400159 BMCWEB_LOG_DEBUG("Post Manager Reset.");
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500160
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400161 std::string resetType;
Jennifer Leeed5befb2018-08-10 11:29:45 -0700162
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400163 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
164 resetType))
165 {
166 return;
167 }
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500168
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400169 if (resetType == "GracefulRestart")
170 {
171 BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
172 doBMCGracefulRestart(asyncResp);
173 return;
174 }
175 if (resetType == "ForceRestart")
176 {
177 BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
178 doBMCForceRestart(asyncResp);
179 return;
180 }
181 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
182 resetType);
183 messages::actionParameterNotSupported(asyncResp->res, resetType,
184 "ResetType");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700185
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400186 return;
187 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700188}
Jennifer Leeed5befb2018-08-10 11:29:45 -0700189
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500190/**
191 * ManagerResetToDefaultsAction class supports POST method for factory reset
192 * action.
193 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700194inline void requestRoutesManagerResetToDefaultsAction(App& app)
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500195{
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500196 /**
197 * Function handles ResetToDefaults POST method request.
198 *
199 * Analyzes POST body message and factory resets BMC by calling
200 * BMC code updater factory reset followed by a BMC reboot.
201 *
202 * BMC code updater factory reset wipes the whole BMC read-write
203 * filesystem which includes things like the network settings.
204 *
205 * OpenBMC only supports ResetToDefaultsType "ResetAll".
206 */
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500207
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700208 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -0700209 "/redfish/v1/Managers/<str>/Actions/Manager.ResetToDefaults/")
Ed Tanoused398212021-06-09 17:05:54 -0700210 .privileges(redfish::privileges::postManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400211 .methods(
212 boost::beast::http::verb::
213 post)([&app](
214 const crow::Request& req,
215 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
216 const std::string& managerId) {
217 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700218 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700219 return;
220 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400221
222 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
223 {
224 messages::resourceNotFound(asyncResp->res, "Manager",
225 managerId);
226 return;
227 }
228
229 BMCWEB_LOG_DEBUG("Post ResetToDefaults.");
230
231 std::optional<std::string> resetType;
232 std::optional<std::string> resetToDefaultsType;
233
Myung Baeafc474a2024-10-09 00:53:29 -0700234 if (!json_util::readJsonAction( //
235 req, asyncResp->res, //
236 "ResetToDefaultsType", resetToDefaultsType, //
237 "ResetType", resetType //
238 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400239 {
240 BMCWEB_LOG_DEBUG("Missing property ResetType.");
241
242 messages::actionParameterMissing(
243 asyncResp->res, "ResetToDefaults", "ResetType");
244 return;
245 }
246
247 if (resetToDefaultsType && !resetType)
248 {
249 BMCWEB_LOG_WARNING(
250 "Using deprecated ResetToDefaultsType, should be ResetType."
251 "Support for the ResetToDefaultsType will be dropped in 2Q24");
252 resetType = resetToDefaultsType;
253 }
254
255 if (resetType != "ResetAll")
256 {
257 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
258 *resetType);
259 messages::actionParameterNotSupported(asyncResp->res,
260 *resetType, "ResetType");
261 return;
262 }
263
264 crow::connections::systemBus->async_method_call(
265 [asyncResp](const boost::system::error_code& ec) {
266 if (ec)
267 {
268 BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec);
269 messages::internalError(asyncResp->res);
270 return;
271 }
272 // Factory Reset doesn't actually happen until a reboot
273 // Can't erase what the BMC is running on
274 doBMCGracefulRestart(asyncResp);
275 },
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -0700276 getBMCUpdateServiceName(), getBMCUpdateServicePath(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400277 "xyz.openbmc_project.Common.FactoryReset", "Reset");
278 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700279}
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500280
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530281/**
282 * ManagerResetActionInfo derived class for delivering Manager
283 * ResetType AllowableValues using ResetInfo schema.
284 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700285inline void requestRoutesManagerResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530286{
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530287 /**
288 * Functions triggers appropriate requests on DBus
289 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700290
Ed Tanous253f11b2024-05-16 09:38:31 -0700291 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700292 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700293 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700294 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700295 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
296 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400297 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
298 {
299 return;
300 }
Ed Tanous14766872022-03-15 10:44:42 -0700301
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400302 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
303 {
304 messages::resourceNotFound(asyncResp->res, "Manager",
305 managerId);
306 return;
307 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700308
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400309 asyncResp->res.jsonValue["@odata.type"] =
310 "#ActionInfo.v1_1_2.ActionInfo";
311 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
312 "/redfish/v1/Managers/{}/ResetActionInfo",
313 BMCWEB_REDFISH_MANAGER_URI_NAME);
314 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
315 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
316 nlohmann::json::object_t parameter;
317 parameter["Name"] = "ResetType";
318 parameter["Required"] = true;
319 parameter["DataType"] = action_info::ParameterTypes::String;
Ed Tanous14766872022-03-15 10:44:42 -0700320
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400321 nlohmann::json::array_t allowableValues;
322 allowableValues.emplace_back("GracefulRestart");
323 allowableValues.emplace_back("ForceRestart");
324 parameter["AllowableValues"] = std::move(allowableValues);
Ed Tanous14766872022-03-15 10:44:42 -0700325
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400326 nlohmann::json::array_t parameters;
327 parameters.emplace_back(std::move(parameter));
Ed Tanous14766872022-03-15 10:44:42 -0700328
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400329 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
330 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700331}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530332
James Feist5b4aa862018-08-16 14:07:01 -0700333static constexpr const char* objectManagerIface =
334 "org.freedesktop.DBus.ObjectManager";
335static constexpr const char* pidConfigurationIface =
336 "xyz.openbmc_project.Configuration.Pid";
337static constexpr const char* pidZoneConfigurationIface =
338 "xyz.openbmc_project.Configuration.Pid.Zone";
James Feistb7a08d02018-12-11 14:55:37 -0800339static constexpr const char* stepwiseConfigurationIface =
340 "xyz.openbmc_project.Configuration.Stepwise";
James Feist73df0db2019-03-25 15:29:35 -0700341static constexpr const char* thermalModeIface =
342 "xyz.openbmc_project.Control.ThermalMode";
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100343
zhanghch058d1b46d2021-04-01 11:18:24 +0800344inline void
345 asyncPopulatePid(const std::string& connection, const std::string& path,
346 const std::string& currentProfile,
347 const std::vector<std::string>& supportedProfiles,
348 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
James Feist5b4aa862018-08-16 14:07:01 -0700349{
George Liu5eb468d2023-06-20 17:03:24 +0800350 sdbusplus::message::object_path objPath(path);
351 dbus::utility::getManagedObjects(
352 connection, objPath,
James Feist73df0db2019-03-25 15:29:35 -0700353 [asyncResp, currentProfile, supportedProfiles](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800354 const boost::system::error_code& ec,
James Feist73df0db2019-03-25 15:29:35 -0700355 const dbus::utility::ManagedObjectType& managedObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400356 if (ec)
James Feist5b4aa862018-08-16 14:07:01 -0700357 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400358 BMCWEB_LOG_ERROR("{}", ec);
359 messages::internalError(asyncResp->res);
360 return;
361 }
362 nlohmann::json& configRoot =
363 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
364 nlohmann::json& fans = configRoot["FanControllers"];
365 fans["@odata.type"] =
366 "#OpenBMCManager.v1_0_0.Manager.FanControllers";
367 fans["@odata.id"] = boost::urls::format(
368 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
369 BMCWEB_REDFISH_MANAGER_URI_NAME);
370
371 nlohmann::json& pids = configRoot["PidControllers"];
372 pids["@odata.type"] =
373 "#OpenBMCManager.v1_0_0.Manager.PidControllers";
374 pids["@odata.id"] = boost::urls::format(
375 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
376 BMCWEB_REDFISH_MANAGER_URI_NAME);
377
378 nlohmann::json& stepwise = configRoot["StepwiseControllers"];
379 stepwise["@odata.type"] =
380 "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
381 stepwise["@odata.id"] = boost::urls::format(
382 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
383 BMCWEB_REDFISH_MANAGER_URI_NAME);
384
385 nlohmann::json& zones = configRoot["FanZones"];
386 zones["@odata.id"] = boost::urls::format(
387 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
388 BMCWEB_REDFISH_MANAGER_URI_NAME);
389 zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
390 configRoot["@odata.id"] =
391 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
392 BMCWEB_REDFISH_MANAGER_URI_NAME);
393 configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
394 configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
395
396 if (!currentProfile.empty())
397 {
398 configRoot["Profile"] = currentProfile;
399 }
400 BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
401
402 for (const auto& pathPair : managedObj)
403 {
404 for (const auto& intfPair : pathPair.second)
James Feist5b4aa862018-08-16 14:07:01 -0700405 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400406 if (intfPair.first != pidConfigurationIface &&
407 intfPair.first != pidZoneConfigurationIface &&
408 intfPair.first != stepwiseConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700409 {
410 continue;
411 }
412
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400413 std::string name;
414
415 for (const std::pair<std::string,
416 dbus::utility::DbusVariantType>&
417 propPair : intfPair.second)
418 {
419 if (propPair.first == "Name")
420 {
421 const std::string* namePtr =
422 std::get_if<std::string>(&propPair.second);
423 if (namePtr == nullptr)
424 {
425 BMCWEB_LOG_ERROR("Pid Name Field illegal");
426 messages::internalError(asyncResp->res);
427 return;
428 }
429 name = *namePtr;
430 dbus::utility::escapePathForDbus(name);
431 }
432 else if (propPair.first == "Profiles")
433 {
434 const std::vector<std::string>* profiles =
435 std::get_if<std::vector<std::string>>(
436 &propPair.second);
437 if (profiles == nullptr)
438 {
439 BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
440 messages::internalError(asyncResp->res);
441 return;
442 }
443 if (std::find(profiles->begin(), profiles->end(),
444 currentProfile) == profiles->end())
445 {
446 BMCWEB_LOG_INFO(
447 "{} not supported in current profile",
448 name);
449 continue;
450 }
451 }
452 }
453 nlohmann::json* config = nullptr;
454 const std::string* classPtr = nullptr;
455
456 for (const std::pair<std::string,
457 dbus::utility::DbusVariantType>&
458 propPair : intfPair.second)
459 {
460 if (propPair.first == "Class")
461 {
462 classPtr =
463 std::get_if<std::string>(&propPair.second);
464 }
465 }
466
467 boost::urls::url url(
468 boost::urls::format("/redfish/v1/Managers/{}",
469 BMCWEB_REDFISH_MANAGER_URI_NAME));
Ed Tanous002d39b2022-05-31 08:59:27 -0700470 if (intfPair.first == pidZoneConfigurationIface)
471 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400472 std::string chassis;
473 if (!dbus::utility::getNthStringFromPath(
474 pathPair.first.str, 5, chassis))
Ed Tanous002d39b2022-05-31 08:59:27 -0700475 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400476 chassis = "#IllegalValue";
477 }
478 nlohmann::json& zone = zones[name];
479 zone["Chassis"]["@odata.id"] = boost::urls::format(
480 "/redfish/v1/Chassis/{}", chassis);
481 url.set_fragment(
482 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
483 .to_string());
484 zone["@odata.id"] = std::move(url);
485 zone["@odata.type"] =
486 "#OpenBMCManager.v1_0_0.Manager.FanZone";
487 config = &zone;
488 }
489
490 else if (intfPair.first == stepwiseConfigurationIface)
491 {
492 if (classPtr == nullptr)
493 {
494 BMCWEB_LOG_ERROR("Pid Class Field illegal");
Ed Tanous002d39b2022-05-31 08:59:27 -0700495 messages::internalError(asyncResp->res);
496 return;
497 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700498
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400499 nlohmann::json& controller = stepwise[name];
500 config = &controller;
501 url.set_fragment(
502 ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
503 name)
504 .to_string());
505 controller["@odata.id"] = std::move(url);
506 controller["@odata.type"] =
507 "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700508
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400509 controller["Direction"] = *classPtr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 }
James Feistb7a08d02018-12-11 14:55:37 -0800511
Ed Tanous002d39b2022-05-31 08:59:27 -0700512 // pid and fans are off the same configuration
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400513 else if (intfPair.first == pidConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700514 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400515 if (classPtr == nullptr)
James Feistb7a08d02018-12-11 14:55:37 -0800516 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400517 BMCWEB_LOG_ERROR("Pid Class Field illegal");
518 messages::internalError(asyncResp->res);
519 return;
James Feist5b4aa862018-08-16 14:07:01 -0700520 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400521 bool isFan = *classPtr == "fan";
522 nlohmann::json& element =
523 isFan ? fans[name] : pids[name];
524 config = &element;
525 if (isFan)
James Feist5b4aa862018-08-16 14:07:01 -0700526 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400527 url.set_fragment(
528 ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
529 name)
530 .to_string());
531 element["@odata.id"] = std::move(url);
532 element["@odata.type"] =
533 "#OpenBMCManager.v1_0_0.Manager.FanController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700534 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400535 else
Ed Tanous002d39b2022-05-31 08:59:27 -0700536 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400537 url.set_fragment(
538 ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
539 name)
540 .to_string());
541 element["@odata.id"] = std::move(url);
542 element["@odata.type"] =
543 "#OpenBMCManager.v1_0_0.Manager.PidController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700544 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400545 }
546 else
547 {
548 BMCWEB_LOG_ERROR("Unexpected configuration");
549 messages::internalError(asyncResp->res);
550 return;
551 }
552
553 // used for making maps out of 2 vectors
554 const std::vector<double>* keys = nullptr;
555 const std::vector<double>* values = nullptr;
556
557 for (const auto& propertyPair : intfPair.second)
558 {
559 if (propertyPair.first == "Type" ||
560 propertyPair.first == "Class" ||
561 propertyPair.first == "Name")
562 {
563 continue;
564 }
565
566 // zones
567 if (intfPair.first == pidZoneConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700568 {
569 const double* ptr =
570 std::get_if<double>(&propertyPair.second);
571 if (ptr == nullptr)
572 {
Ed Tanous62598e32023-07-17 17:06:25 -0700573 BMCWEB_LOG_ERROR("Field Illegal {}",
574 propertyPair.first);
Ed Tanous002d39b2022-05-31 08:59:27 -0700575 messages::internalError(asyncResp->res);
576 return;
577 }
578 (*config)[propertyPair.first] = *ptr;
James Feist5b4aa862018-08-16 14:07:01 -0700579 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400580
581 if (intfPair.first == stepwiseConfigurationIface)
582 {
583 if (propertyPair.first == "Reading" ||
584 propertyPair.first == "Output")
585 {
586 const std::vector<double>* ptr =
587 std::get_if<std::vector<double>>(
588 &propertyPair.second);
589
590 if (ptr == nullptr)
591 {
592 BMCWEB_LOG_ERROR("Field Illegal {}",
593 propertyPair.first);
594 messages::internalError(asyncResp->res);
595 return;
596 }
597
598 if (propertyPair.first == "Reading")
599 {
600 keys = ptr;
601 }
602 else
603 {
604 values = ptr;
605 }
606 if (keys != nullptr && values != nullptr)
607 {
608 if (keys->size() != values->size())
609 {
610 BMCWEB_LOG_ERROR(
611 "Reading and Output size don't match ");
612 messages::internalError(asyncResp->res);
613 return;
614 }
615 nlohmann::json& steps = (*config)["Steps"];
616 steps = nlohmann::json::array();
617 for (size_t ii = 0; ii < keys->size(); ii++)
618 {
619 nlohmann::json::object_t step;
620 step["Target"] = (*keys)[ii];
621 step["Output"] = (*values)[ii];
622 steps.emplace_back(std::move(step));
623 }
624 }
625 }
626 if (propertyPair.first == "NegativeHysteresis" ||
627 propertyPair.first == "PositiveHysteresis")
628 {
629 const double* ptr =
630 std::get_if<double>(&propertyPair.second);
631 if (ptr == nullptr)
632 {
633 BMCWEB_LOG_ERROR("Field Illegal {}",
634 propertyPair.first);
635 messages::internalError(asyncResp->res);
636 return;
637 }
638 (*config)[propertyPair.first] = *ptr;
639 }
640 }
641
642 // pid and fans are off the same configuration
643 if (intfPair.first == pidConfigurationIface ||
644 intfPair.first == stepwiseConfigurationIface)
645 {
646 if (propertyPair.first == "Zones")
647 {
648 const std::vector<std::string>* inputs =
649 std::get_if<std::vector<std::string>>(
650 &propertyPair.second);
651
652 if (inputs == nullptr)
653 {
654 BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
655 messages::internalError(asyncResp->res);
656 return;
657 }
658 auto& data = (*config)[propertyPair.first];
659 data = nlohmann::json::array();
660 for (std::string itemCopy : *inputs)
661 {
662 dbus::utility::escapePathForDbus(itemCopy);
663 nlohmann::json::object_t input;
664 boost::urls::url managerUrl =
665 boost::urls::format(
666 "/redfish/v1/Managers/{}#{}",
667 BMCWEB_REDFISH_MANAGER_URI_NAME,
668 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
669 itemCopy)
670 .to_string());
671 input["@odata.id"] = std::move(managerUrl);
672 data.emplace_back(std::move(input));
673 }
674 }
675 // todo(james): may never happen, but this
676 // assumes configuration data referenced in the
677 // PID config is provided by the same daemon, we
678 // could add another loop to cover all cases,
679 // but I'm okay kicking this can down the road a
680 // bit
681
682 else if (propertyPair.first == "Inputs" ||
683 propertyPair.first == "Outputs")
684 {
685 auto& data = (*config)[propertyPair.first];
686 const std::vector<std::string>* inputs =
687 std::get_if<std::vector<std::string>>(
688 &propertyPair.second);
689
690 if (inputs == nullptr)
691 {
692 BMCWEB_LOG_ERROR("Field Illegal {}",
693 propertyPair.first);
694 messages::internalError(asyncResp->res);
695 return;
696 }
697 data = *inputs;
698 }
699 else if (propertyPair.first == "SetPointOffset")
700 {
701 const std::string* ptr =
702 std::get_if<std::string>(
703 &propertyPair.second);
704
705 if (ptr == nullptr)
706 {
707 BMCWEB_LOG_ERROR("Field Illegal {}",
708 propertyPair.first);
709 messages::internalError(asyncResp->res);
710 return;
711 }
712 // translate from dbus to redfish
713 if (*ptr == "WarningHigh")
714 {
715 (*config)["SetPointOffset"] =
716 "UpperThresholdNonCritical";
717 }
718 else if (*ptr == "WarningLow")
719 {
720 (*config)["SetPointOffset"] =
721 "LowerThresholdNonCritical";
722 }
723 else if (*ptr == "CriticalHigh")
724 {
725 (*config)["SetPointOffset"] =
726 "UpperThresholdCritical";
727 }
728 else if (*ptr == "CriticalLow")
729 {
730 (*config)["SetPointOffset"] =
731 "LowerThresholdCritical";
732 }
733 else
734 {
735 BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
736 messages::internalError(asyncResp->res);
737 return;
738 }
739 }
740 // doubles
741 else if (propertyPair.first ==
742 "FFGainCoefficient" ||
743 propertyPair.first == "FFOffCoefficient" ||
744 propertyPair.first == "ICoefficient" ||
745 propertyPair.first == "ILimitMax" ||
746 propertyPair.first == "ILimitMin" ||
747 propertyPair.first ==
748 "PositiveHysteresis" ||
749 propertyPair.first ==
750 "NegativeHysteresis" ||
751 propertyPair.first == "OutLimitMax" ||
752 propertyPair.first == "OutLimitMin" ||
753 propertyPair.first == "PCoefficient" ||
754 propertyPair.first == "SetPoint" ||
755 propertyPair.first == "SlewNeg" ||
756 propertyPair.first == "SlewPos")
757 {
758 const double* ptr =
759 std::get_if<double>(&propertyPair.second);
760 if (ptr == nullptr)
761 {
762 BMCWEB_LOG_ERROR("Field Illegal {}",
763 propertyPair.first);
764 messages::internalError(asyncResp->res);
765 return;
766 }
767 (*config)[propertyPair.first] = *ptr;
768 }
769 }
James Feist5b4aa862018-08-16 14:07:01 -0700770 }
771 }
772 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400773 });
James Feist5b4aa862018-08-16 14:07:01 -0700774}
Jennifer Leeca537922018-08-10 10:07:30 -0700775
James Feist83ff9ab2018-08-31 10:18:24 -0700776enum class CreatePIDRet
777{
778 fail,
779 del,
780 patch
781};
782
zhanghch058d1b46d2021-04-01 11:18:24 +0800783inline bool
784 getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800785 std::vector<nlohmann::json::object_t>& config,
zhanghch058d1b46d2021-04-01 11:18:24 +0800786 std::vector<std::string>& zones)
James Feist5f2caae2018-12-12 14:08:25 -0800787{
James Feistb6baeaa2019-02-21 10:41:40 -0800788 if (config.empty())
789 {
Ed Tanous62598e32023-07-17 17:06:25 -0700790 BMCWEB_LOG_ERROR("Empty Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700791 messages::propertyValueFormatError(response->res, config, "Zones");
James Feistb6baeaa2019-02-21 10:41:40 -0800792 return false;
793 }
James Feist5f2caae2018-12-12 14:08:25 -0800794 for (auto& odata : config)
795 {
796 std::string path;
Ed Tanous9e9b6042024-03-06 14:18:28 -0800797 if (!redfish::json_util::readJsonObject(odata, response->res,
798 "@odata.id", path))
James Feist5f2caae2018-12-12 14:08:25 -0800799 {
800 return false;
801 }
802 std::string input;
James Feist61adbda2019-03-25 13:03:51 -0700803
804 // 8 below comes from
805 // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
806 // 0 1 2 3 4 5 6 7 8
807 if (!dbus::utility::getNthStringFromPath(path, 8, input))
James Feist5f2caae2018-12-12 14:08:25 -0800808 {
Ed Tanous62598e32023-07-17 17:06:25 -0700809 BMCWEB_LOG_ERROR("Got invalid path {}", path);
810 BMCWEB_LOG_ERROR("Illegal Type Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700811 messages::propertyValueFormatError(response->res, odata, "Zones");
James Feist5f2caae2018-12-12 14:08:25 -0800812 return false;
813 }
Ed Tanousa170f272022-06-30 21:53:27 -0700814 std::replace(input.begin(), input.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -0800815 zones.emplace_back(std::move(input));
816 }
817 return true;
818}
819
Ed Tanous711ac7a2021-12-20 09:34:41 -0800820inline const dbus::utility::ManagedObjectType::value_type*
James Feist73df0db2019-03-25 15:29:35 -0700821 findChassis(const dbus::utility::ManagedObjectType& managedObj,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800822 std::string_view value, std::string& chassis)
James Feistb6baeaa2019-02-21 10:41:40 -0800823{
Ed Tanous62598e32023-07-17 17:06:25 -0700824 BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
James Feistb6baeaa2019-02-21 10:41:40 -0800825
Ed Tanous9e9b6042024-03-06 14:18:28 -0800826 std::string escaped(value);
Yaswanth Reddy M6ce82fa2023-03-10 07:29:45 +0000827 std::replace(escaped.begin(), escaped.end(), ' ', '_');
James Feistb6baeaa2019-02-21 10:41:40 -0800828 escaped = "/" + escaped;
Ed Tanous3544d2a2023-08-06 18:12:20 -0700829 auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
Ed Tanous18f8f602023-07-18 10:07:23 -0700830 if (obj.first.str.ends_with(escaped))
Ed Tanous002d39b2022-05-31 08:59:27 -0700831 {
Ed Tanous62598e32023-07-17 17:06:25 -0700832 BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700833 return true;
834 }
835 return false;
836 });
James Feistb6baeaa2019-02-21 10:41:40 -0800837
838 if (it == managedObj.end())
839 {
James Feist73df0db2019-03-25 15:29:35 -0700840 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800841 }
842 // 5 comes from <chassis-name> being the 5th element
843 // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
James Feist73df0db2019-03-25 15:29:35 -0700844 if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
845 {
846 return &(*it);
847 }
848
849 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800850}
851
Ed Tanous23a21a12020-07-25 04:45:05 +0000852inline CreatePIDRet createPidInterface(
zhanghch058d1b46d2021-04-01 11:18:24 +0800853 const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800854 std::string_view name, nlohmann::json& jsonValue, const std::string& path,
James Feist83ff9ab2018-08-31 10:18:24 -0700855 const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800856 dbus::utility::DBusPropertiesMap& output, std::string& chassis,
857 const std::string& profile)
James Feist83ff9ab2018-08-31 10:18:24 -0700858{
James Feist5f2caae2018-12-12 14:08:25 -0800859 // common deleter
Ed Tanous9e9b6042024-03-06 14:18:28 -0800860 if (jsonValue == nullptr)
James Feist5f2caae2018-12-12 14:08:25 -0800861 {
862 std::string iface;
863 if (type == "PidControllers" || type == "FanControllers")
864 {
865 iface = pidConfigurationIface;
866 }
867 else if (type == "FanZones")
868 {
869 iface = pidZoneConfigurationIface;
870 }
871 else if (type == "StepwiseControllers")
872 {
873 iface = stepwiseConfigurationIface;
874 }
875 else
876 {
Ed Tanous62598e32023-07-17 17:06:25 -0700877 BMCWEB_LOG_ERROR("Illegal Type {}", type);
James Feist5f2caae2018-12-12 14:08:25 -0800878 messages::propertyUnknown(response->res, type);
879 return CreatePIDRet::fail;
880 }
James Feist6ee7f772020-02-06 16:25:27 -0800881
Ed Tanous62598e32023-07-17 17:06:25 -0700882 BMCWEB_LOG_DEBUG("del {} {}", path, iface);
James Feist5f2caae2018-12-12 14:08:25 -0800883 // delete interface
884 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800885 [response, path](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400886 if (ec)
887 {
888 BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
889 messages::internalError(response->res);
890 return;
891 }
892 messages::success(response->res);
893 },
James Feist5f2caae2018-12-12 14:08:25 -0800894 "xyz.openbmc_project.EntityManager", path, iface, "Delete");
895 return CreatePIDRet::del;
896 }
897
Ed Tanous711ac7a2021-12-20 09:34:41 -0800898 const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800899 if (!createNewObject)
900 {
901 // if we aren't creating a new object, we should be able to find it on
902 // d-bus
Ed Tanous9e9b6042024-03-06 14:18:28 -0800903 managedItem = findChassis(managedObj, name, chassis);
James Feist73df0db2019-03-25 15:29:35 -0700904 if (managedItem == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -0800905 {
Ed Tanous62598e32023-07-17 17:06:25 -0700906 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousef4c65b2023-04-24 15:28:50 -0700907 messages::invalidObject(
908 response->res,
909 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -0800910 return CreatePIDRet::fail;
911 }
912 }
913
Ed Tanous26f69762022-01-25 09:49:11 -0800914 if (!profile.empty() &&
James Feist73df0db2019-03-25 15:29:35 -0700915 (type == "PidControllers" || type == "FanControllers" ||
916 type == "StepwiseControllers"))
917 {
918 if (managedItem == nullptr)
919 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800920 output.emplace_back("Profiles", std::vector<std::string>{profile});
James Feist73df0db2019-03-25 15:29:35 -0700921 }
922 else
923 {
924 std::string interface;
925 if (type == "StepwiseControllers")
926 {
927 interface = stepwiseConfigurationIface;
928 }
929 else
930 {
931 interface = pidConfigurationIface;
932 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800933 bool ifaceFound = false;
934 for (const auto& iface : managedItem->second)
935 {
936 if (iface.first == interface)
937 {
938 ifaceFound = true;
939 for (const auto& prop : iface.second)
940 {
941 if (prop.first == "Profiles")
942 {
943 const std::vector<std::string>* curProfiles =
944 std::get_if<std::vector<std::string>>(
945 &(prop.second));
946 if (curProfiles == nullptr)
947 {
Ed Tanous62598e32023-07-17 17:06:25 -0700948 BMCWEB_LOG_ERROR(
949 "Illegal profiles in managed object");
Ed Tanous711ac7a2021-12-20 09:34:41 -0800950 messages::internalError(response->res);
951 return CreatePIDRet::fail;
952 }
953 if (std::find(curProfiles->begin(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400954 curProfiles->end(), profile) ==
955 curProfiles->end())
Ed Tanous711ac7a2021-12-20 09:34:41 -0800956 {
957 std::vector<std::string> newProfiles =
958 *curProfiles;
959 newProfiles.push_back(profile);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800960 output.emplace_back("Profiles", newProfiles);
Ed Tanous711ac7a2021-12-20 09:34:41 -0800961 }
962 }
963 }
964 }
965 }
966
967 if (!ifaceFound)
James Feist73df0db2019-03-25 15:29:35 -0700968 {
Ed Tanous62598e32023-07-17 17:06:25 -0700969 BMCWEB_LOG_ERROR("Failed to find interface in managed object");
James Feist73df0db2019-03-25 15:29:35 -0700970 messages::internalError(response->res);
971 return CreatePIDRet::fail;
972 }
James Feist73df0db2019-03-25 15:29:35 -0700973 }
974 }
975
James Feist83ff9ab2018-08-31 10:18:24 -0700976 if (type == "PidControllers" || type == "FanControllers")
977 {
978 if (createNewObject)
979 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800980 output.emplace_back("Class",
981 type == "PidControllers" ? "temp" : "fan");
982 output.emplace_back("Type", "Pid");
James Feist83ff9ab2018-08-31 10:18:24 -0700983 }
James Feist5f2caae2018-12-12 14:08:25 -0800984
Ed Tanous9e9b6042024-03-06 14:18:28 -0800985 std::optional<std::vector<nlohmann::json::object_t>> zones;
James Feist5f2caae2018-12-12 14:08:25 -0800986 std::optional<std::vector<std::string>> inputs;
987 std::optional<std::vector<std::string>> outputs;
988 std::map<std::string, std::optional<double>> doubles;
James Feistb943aae2019-07-11 16:33:56 -0700989 std::optional<std::string> setpointOffset;
Myung Baeafc474a2024-10-09 00:53:29 -0700990 if (!redfish::json_util::readJson( //
991 jsonValue, response->res, //
992 "FFGainCoefficient", doubles["FFGainCoefficient"], //
993 "FFOffCoefficient", doubles["FFOffCoefficient"], //
994 "ICoefficient", doubles["ICoefficient"], //
995 "ILimitMax", doubles["ILimitMax"], //
996 "ILimitMin", doubles["ILimitMin"], //
997 "Inputs", inputs, //
998 "NegativeHysteresis", doubles["NegativeHysteresis"], //
999 "OutLimitMax", doubles["OutLimitMax"], //
1000 "OutLimitMin", doubles["OutLimitMin"], //
1001 "Outputs", outputs, //
1002 "PCoefficient", doubles["PCoefficient"], //
1003 "PositiveHysteresis", doubles["PositiveHysteresis"], //
1004 "SetPoint", doubles["SetPoint"], //
1005 "SetPointOffset", setpointOffset, //
1006 "SlewNeg", doubles["SlewNeg"], //
1007 "SlewPos", doubles["SlewPos"], //
1008 "Zones", zones //
1009 ))
James Feist83ff9ab2018-08-31 10:18:24 -07001010 {
James Feist5f2caae2018-12-12 14:08:25 -08001011 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -07001012 }
Myung Baeafc474a2024-10-09 00:53:29 -07001013
James Feist5f2caae2018-12-12 14:08:25 -08001014 if (zones)
James Feist83ff9ab2018-08-31 10:18:24 -07001015 {
James Feist5f2caae2018-12-12 14:08:25 -08001016 std::vector<std::string> zonesStr;
1017 if (!getZonesFromJsonReq(response, *zones, zonesStr))
James Feist83ff9ab2018-08-31 10:18:24 -07001018 {
Ed Tanous62598e32023-07-17 17:06:25 -07001019 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001020 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -07001021 }
James Feistb6baeaa2019-02-21 10:41:40 -08001022 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001023 findChassis(managedObj, zonesStr[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001024 {
Ed Tanous62598e32023-07-17 17:06:25 -07001025 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001026 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001027 response->res,
1028 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001029 return CreatePIDRet::fail;
1030 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001031 output.emplace_back("Zones", std::move(zonesStr));
James Feist5f2caae2018-12-12 14:08:25 -08001032 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001033
1034 if (inputs)
James Feist5f2caae2018-12-12 14:08:25 -08001035 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001036 for (std::string& value : *inputs)
James Feist83ff9ab2018-08-31 10:18:24 -07001037 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001038 std::replace(value.begin(), value.end(), '_', ' ');
James Feist83ff9ab2018-08-31 10:18:24 -07001039 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001040 output.emplace_back("Inputs", *inputs);
1041 }
1042
1043 if (outputs)
1044 {
1045 for (std::string& value : *outputs)
1046 {
1047 std::replace(value.begin(), value.end(), '_', ' ');
1048 }
1049 output.emplace_back("Outputs", *outputs);
James Feist5f2caae2018-12-12 14:08:25 -08001050 }
James Feist83ff9ab2018-08-31 10:18:24 -07001051
James Feistb943aae2019-07-11 16:33:56 -07001052 if (setpointOffset)
1053 {
1054 // translate between redfish and dbus names
1055 if (*setpointOffset == "UpperThresholdNonCritical")
1056 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001057 output.emplace_back("SetPointOffset", "WarningLow");
James Feistb943aae2019-07-11 16:33:56 -07001058 }
1059 else if (*setpointOffset == "LowerThresholdNonCritical")
1060 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001061 output.emplace_back("SetPointOffset", "WarningHigh");
James Feistb943aae2019-07-11 16:33:56 -07001062 }
1063 else if (*setpointOffset == "LowerThresholdCritical")
1064 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001065 output.emplace_back("SetPointOffset", "CriticalLow");
James Feistb943aae2019-07-11 16:33:56 -07001066 }
1067 else if (*setpointOffset == "UpperThresholdCritical")
1068 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001069 output.emplace_back("SetPointOffset", "CriticalHigh");
James Feistb943aae2019-07-11 16:33:56 -07001070 }
1071 else
1072 {
Ed Tanous62598e32023-07-17 17:06:25 -07001073 BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
Ed Tanous9e9b6042024-03-06 14:18:28 -08001074 messages::propertyValueNotInList(response->res, name,
Ed Tanousace85d62021-10-26 12:45:59 -07001075 "SetPointOffset");
James Feistb943aae2019-07-11 16:33:56 -07001076 return CreatePIDRet::fail;
1077 }
1078 }
1079
James Feist5f2caae2018-12-12 14:08:25 -08001080 // doubles
1081 for (const auto& pairs : doubles)
1082 {
1083 if (!pairs.second)
James Feist83ff9ab2018-08-31 10:18:24 -07001084 {
James Feist5f2caae2018-12-12 14:08:25 -08001085 continue;
James Feist83ff9ab2018-08-31 10:18:24 -07001086 }
Ed Tanous62598e32023-07-17 17:06:25 -07001087 BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -08001088 output.emplace_back(pairs.first, *pairs.second);
James Feist83ff9ab2018-08-31 10:18:24 -07001089 }
1090 }
James Feist5f2caae2018-12-12 14:08:25 -08001091
James Feist83ff9ab2018-08-31 10:18:24 -07001092 else if (type == "FanZones")
1093 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001094 output.emplace_back("Type", "Pid.Zone");
James Feist83ff9ab2018-08-31 10:18:24 -07001095
Ed Tanous9e9b6042024-03-06 14:18:28 -08001096 std::optional<std::string> chassisId;
James Feist5f2caae2018-12-12 14:08:25 -08001097 std::optional<double> failSafePercent;
James Feistd3ec07f2019-02-25 14:51:15 -08001098 std::optional<double> minThermalOutput;
Myung Baeafc474a2024-10-09 00:53:29 -07001099 if (!redfish::json_util::readJson( //
1100 jsonValue, response->res, //
1101 "Chassis/@odata.id", chassisId, //
1102 "FailSafePercent", failSafePercent, //
1103 "MinThermalOutput", minThermalOutput))
James Feist83ff9ab2018-08-31 10:18:24 -07001104 {
James Feist5f2caae2018-12-12 14:08:25 -08001105 return CreatePIDRet::fail;
1106 }
James Feist83ff9ab2018-08-31 10:18:24 -07001107
Ed Tanous9e9b6042024-03-06 14:18:28 -08001108 if (chassisId)
James Feist5f2caae2018-12-12 14:08:25 -08001109 {
AppaRao Puli717794d2019-10-18 22:54:53 +05301110 // /redfish/v1/chassis/chassis_name/
Ed Tanous9e9b6042024-03-06 14:18:28 -08001111 if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
James Feist5f2caae2018-12-12 14:08:25 -08001112 {
Ed Tanous9e9b6042024-03-06 14:18:28 -08001113 BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
Ed Tanousace85d62021-10-26 12:45:59 -07001114 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001115 response->res,
Ed Tanous9e9b6042024-03-06 14:18:28 -08001116 boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
James Feist5f2caae2018-12-12 14:08:25 -08001117 return CreatePIDRet::fail;
1118 }
1119 }
James Feistd3ec07f2019-02-25 14:51:15 -08001120 if (minThermalOutput)
James Feist5f2caae2018-12-12 14:08:25 -08001121 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001122 output.emplace_back("MinThermalOutput", *minThermalOutput);
James Feist5f2caae2018-12-12 14:08:25 -08001123 }
1124 if (failSafePercent)
1125 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001126 output.emplace_back("FailSafePercent", *failSafePercent);
James Feist5f2caae2018-12-12 14:08:25 -08001127 }
1128 }
1129 else if (type == "StepwiseControllers")
1130 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001131 output.emplace_back("Type", "Stepwise");
James Feist5f2caae2018-12-12 14:08:25 -08001132
Ed Tanous9e9b6042024-03-06 14:18:28 -08001133 std::optional<std::vector<nlohmann::json::object_t>> zones;
1134 std::optional<std::vector<nlohmann::json::object_t>> steps;
James Feist5f2caae2018-12-12 14:08:25 -08001135 std::optional<std::vector<std::string>> inputs;
1136 std::optional<double> positiveHysteresis;
1137 std::optional<double> negativeHysteresis;
James Feistc33a90e2019-03-01 10:17:44 -08001138 std::optional<std::string> direction; // upper clipping curve vs lower
Myung Baeafc474a2024-10-09 00:53:29 -07001139 if (!redfish::json_util::readJson( //
1140 jsonValue, response->res, //
1141 "Direction", direction, //
1142 "Inputs", inputs, //
1143 "NegativeHysteresis", negativeHysteresis, //
1144 "PositiveHysteresis", positiveHysteresis, //
1145 "Steps", steps, //
1146 "Zones", zones //
1147 ))
James Feist5f2caae2018-12-12 14:08:25 -08001148 {
James Feist5f2caae2018-12-12 14:08:25 -08001149 return CreatePIDRet::fail;
1150 }
1151
1152 if (zones)
1153 {
James Feistb6baeaa2019-02-21 10:41:40 -08001154 std::vector<std::string> zonesStrs;
1155 if (!getZonesFromJsonReq(response, *zones, zonesStrs))
James Feist5f2caae2018-12-12 14:08:25 -08001156 {
Ed Tanous62598e32023-07-17 17:06:25 -07001157 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001158 return CreatePIDRet::fail;
1159 }
James Feistb6baeaa2019-02-21 10:41:40 -08001160 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001161 findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001162 {
Ed Tanous62598e32023-07-17 17:06:25 -07001163 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001164 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001165 response->res,
1166 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001167 return CreatePIDRet::fail;
1168 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001169 output.emplace_back("Zones", std::move(zonesStrs));
James Feist5f2caae2018-12-12 14:08:25 -08001170 }
1171 if (steps)
1172 {
1173 std::vector<double> readings;
1174 std::vector<double> outputs;
1175 for (auto& step : *steps)
1176 {
Ed Tanous543f4402022-01-06 13:12:53 -08001177 double target = 0.0;
1178 double out = 0.0;
James Feist5f2caae2018-12-12 14:08:25 -08001179
Myung Baeafc474a2024-10-09 00:53:29 -07001180 if (!redfish::json_util::readJsonObject( //
1181 step, response->res, //
1182 "Output", out, //
1183 "Target", target //
1184 ))
James Feist5f2caae2018-12-12 14:08:25 -08001185 {
James Feist5f2caae2018-12-12 14:08:25 -08001186 return CreatePIDRet::fail;
1187 }
1188 readings.emplace_back(target);
Ed Tanous23a21a12020-07-25 04:45:05 +00001189 outputs.emplace_back(out);
James Feist5f2caae2018-12-12 14:08:25 -08001190 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001191 output.emplace_back("Reading", std::move(readings));
1192 output.emplace_back("Output", std::move(outputs));
James Feist5f2caae2018-12-12 14:08:25 -08001193 }
1194 if (inputs)
1195 {
1196 for (std::string& value : *inputs)
1197 {
Ed Tanousa170f272022-06-30 21:53:27 -07001198 std::replace(value.begin(), value.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -08001199 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001200 output.emplace_back("Inputs", std::move(*inputs));
James Feist5f2caae2018-12-12 14:08:25 -08001201 }
1202 if (negativeHysteresis)
1203 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001204 output.emplace_back("NegativeHysteresis", *negativeHysteresis);
James Feist5f2caae2018-12-12 14:08:25 -08001205 }
1206 if (positiveHysteresis)
1207 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001208 output.emplace_back("PositiveHysteresis", *positiveHysteresis);
James Feist83ff9ab2018-08-31 10:18:24 -07001209 }
James Feistc33a90e2019-03-01 10:17:44 -08001210 if (direction)
1211 {
1212 constexpr const std::array<const char*, 2> allowedDirections = {
1213 "Ceiling", "Floor"};
Ed Tanous3544d2a2023-08-06 18:12:20 -07001214 if (std::ranges::find(allowedDirections, *direction) ==
1215 allowedDirections.end())
James Feistc33a90e2019-03-01 10:17:44 -08001216 {
1217 messages::propertyValueTypeError(response->res, "Direction",
1218 *direction);
1219 return CreatePIDRet::fail;
1220 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001221 output.emplace_back("Class", *direction);
James Feistc33a90e2019-03-01 10:17:44 -08001222 }
James Feist83ff9ab2018-08-31 10:18:24 -07001223 }
1224 else
1225 {
Ed Tanous62598e32023-07-17 17:06:25 -07001226 BMCWEB_LOG_ERROR("Illegal Type {}", type);
Jason M. Bills35a62c72018-10-09 12:45:45 -07001227 messages::propertyUnknown(response->res, type);
James Feist83ff9ab2018-08-31 10:18:24 -07001228 return CreatePIDRet::fail;
1229 }
1230 return CreatePIDRet::patch;
1231}
James Feist73df0db2019-03-25 15:29:35 -07001232struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
1233{
Ed Tanous6936afe2022-09-08 15:10:39 -07001234 struct CompletionValues
1235 {
1236 std::vector<std::string> supportedProfiles;
1237 std::string currentProfile;
1238 dbus::utility::MapperGetSubTreeResponse subtree;
1239 };
James Feist73df0db2019-03-25 15:29:35 -07001240
Ed Tanous4e23a442022-06-06 09:57:26 -07001241 explicit GetPIDValues(
1242 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +00001243 asyncResp(asyncRespIn)
James Feist73df0db2019-03-25 15:29:35 -07001244
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001245 {}
James Feist73df0db2019-03-25 15:29:35 -07001246
1247 void run()
1248 {
1249 std::shared_ptr<GetPIDValues> self = shared_from_this();
1250
1251 // get all configurations
George Liue99073f2022-12-09 11:06:16 +08001252 constexpr std::array<std::string_view, 4> interfaces = {
1253 pidConfigurationIface, pidZoneConfigurationIface,
1254 objectManagerIface, stepwiseConfigurationIface};
1255 dbus::utility::getSubTree(
1256 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001257 [self](
George Liue99073f2022-12-09 11:06:16 +08001258 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001259 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001260 if (ec)
1261 {
1262 BMCWEB_LOG_ERROR("{}", ec);
1263 messages::internalError(self->asyncResp->res);
1264 return;
1265 }
1266 self->complete.subtree = subtreeLocal;
1267 });
James Feist73df0db2019-03-25 15:29:35 -07001268
1269 // at the same time get the selected profile
George Liue99073f2022-12-09 11:06:16 +08001270 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1271 thermalModeIface};
1272 dbus::utility::getSubTree(
1273 "/", 0, thermalModeIfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001274 [self](
George Liue99073f2022-12-09 11:06:16 +08001275 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001276 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001277 if (ec || subtreeLocal.empty())
James Feist73df0db2019-03-25 15:29:35 -07001278 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001279 return;
1280 }
1281 if (subtreeLocal[0].second.size() != 1)
1282 {
1283 // invalid mapper response, should never happen
1284 BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
James Feist73df0db2019-03-25 15:29:35 -07001285 messages::internalError(self->asyncResp->res);
1286 return;
1287 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001288
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001289 const std::string& path = subtreeLocal[0].first;
1290 const std::string& owner = subtreeLocal[0].second[0].first;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001291
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001292 sdbusplus::asio::getAllProperties(
1293 *crow::connections::systemBus, owner, path,
1294 thermalModeIface,
1295 [path, owner,
1296 self](const boost::system::error_code& ec2,
1297 const dbus::utility::DBusPropertiesMap& resp) {
1298 if (ec2)
1299 {
1300 BMCWEB_LOG_ERROR(
1301 "GetPIDValues: Can't get thermalModeIface {}",
1302 path);
1303 messages::internalError(self->asyncResp->res);
1304 return;
1305 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001306
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001307 const std::string* current = nullptr;
1308 const std::vector<std::string>* supported = nullptr;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001309
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001310 const bool success = sdbusplus::unpackPropertiesNoThrow(
1311 dbus_utils::UnpackErrorPrinter(), resp, "Current",
1312 current, "Supported", supported);
1313
1314 if (!success)
1315 {
1316 messages::internalError(self->asyncResp->res);
1317 return;
1318 }
1319
1320 if (current == nullptr || supported == nullptr)
1321 {
1322 BMCWEB_LOG_ERROR(
1323 "GetPIDValues: thermal mode iface invalid {}",
1324 path);
1325 messages::internalError(self->asyncResp->res);
1326 return;
1327 }
1328 self->complete.currentProfile = *current;
1329 self->complete.supportedProfiles = *supported;
1330 });
George Liue99073f2022-12-09 11:06:16 +08001331 });
James Feist73df0db2019-03-25 15:29:35 -07001332 }
1333
Ed Tanous6936afe2022-09-08 15:10:39 -07001334 static void
1335 processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1336 const CompletionValues& completion)
James Feist73df0db2019-03-25 15:29:35 -07001337 {
1338 if (asyncResp->res.result() != boost::beast::http::status::ok)
1339 {
1340 return;
1341 }
1342 // create map of <connection, path to objMgr>>
Ed Tanous6936afe2022-09-08 15:10:39 -07001343 boost::container::flat_map<
1344 std::string, std::string, std::less<>,
1345 std::vector<std::pair<std::string, std::string>>>
1346 objectMgrPaths;
1347 boost::container::flat_set<std::string, std::less<>,
1348 std::vector<std::string>>
1349 calledConnections;
1350 for (const auto& pathGroup : completion.subtree)
James Feist73df0db2019-03-25 15:29:35 -07001351 {
1352 for (const auto& connectionGroup : pathGroup.second)
1353 {
1354 auto findConnection =
1355 calledConnections.find(connectionGroup.first);
1356 if (findConnection != calledConnections.end())
1357 {
1358 break;
1359 }
1360 for (const std::string& interface : connectionGroup.second)
1361 {
1362 if (interface == objectManagerIface)
1363 {
1364 objectMgrPaths[connectionGroup.first] = pathGroup.first;
1365 }
1366 // this list is alphabetical, so we
1367 // should have found the objMgr by now
1368 if (interface == pidConfigurationIface ||
1369 interface == pidZoneConfigurationIface ||
1370 interface == stepwiseConfigurationIface)
1371 {
1372 auto findObjMgr =
1373 objectMgrPaths.find(connectionGroup.first);
1374 if (findObjMgr == objectMgrPaths.end())
1375 {
Ed Tanous62598e32023-07-17 17:06:25 -07001376 BMCWEB_LOG_DEBUG("{}Has no Object Manager",
1377 connectionGroup.first);
James Feist73df0db2019-03-25 15:29:35 -07001378 continue;
1379 }
1380
1381 calledConnections.insert(connectionGroup.first);
1382
1383 asyncPopulatePid(findObjMgr->first, findObjMgr->second,
Ed Tanous6936afe2022-09-08 15:10:39 -07001384 completion.currentProfile,
1385 completion.supportedProfiles,
James Feist73df0db2019-03-25 15:29:35 -07001386 asyncResp);
1387 break;
1388 }
1389 }
1390 }
1391 }
1392 }
1393
Ed Tanous6936afe2022-09-08 15:10:39 -07001394 ~GetPIDValues()
1395 {
1396 boost::asio::post(crow::connections::systemBus->get_io_context(),
1397 std::bind_front(&processingComplete, asyncResp,
1398 std::move(complete)));
1399 }
1400
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001401 GetPIDValues(const GetPIDValues&) = delete;
1402 GetPIDValues(GetPIDValues&&) = delete;
1403 GetPIDValues& operator=(const GetPIDValues&) = delete;
1404 GetPIDValues& operator=(GetPIDValues&&) = delete;
1405
zhanghch058d1b46d2021-04-01 11:18:24 +08001406 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous6936afe2022-09-08 15:10:39 -07001407 CompletionValues complete;
James Feist73df0db2019-03-25 15:29:35 -07001408};
1409
1410struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
1411{
Ed Tanous9e9b6042024-03-06 14:18:28 -08001412 SetPIDValues(
1413 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1414 std::vector<
1415 std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
1416 configurationsIn,
1417 std::optional<std::string>& profileIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001418 asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
Ed Tanous9e9b6042024-03-06 14:18:28 -08001419 profile(std::move(profileIn))
1420 {}
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001421
1422 SetPIDValues(const SetPIDValues&) = delete;
1423 SetPIDValues(SetPIDValues&&) = delete;
1424 SetPIDValues& operator=(const SetPIDValues&) = delete;
1425 SetPIDValues& operator=(SetPIDValues&&) = delete;
1426
James Feist73df0db2019-03-25 15:29:35 -07001427 void run()
1428 {
1429 if (asyncResp->res.result() != boost::beast::http::status::ok)
1430 {
1431 return;
1432 }
1433
1434 std::shared_ptr<SetPIDValues> self = shared_from_this();
1435
1436 // todo(james): might make sense to do a mapper call here if this
1437 // interface gets more traction
George Liu5eb468d2023-06-20 17:03:24 +08001438 sdbusplus::message::object_path objPath(
1439 "/xyz/openbmc_project/inventory");
1440 dbus::utility::getManagedObjects(
1441 "xyz.openbmc_project.EntityManager", objPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001442 [self](const boost::system::error_code& ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001443 const dbus::utility::ManagedObjectType& mObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001444 if (ec)
James Feiste69d9de2020-02-07 12:23:27 -08001445 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001446 BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
1447 messages::internalError(self->asyncResp->res);
1448 return;
1449 }
1450 const std::array<const char*, 3> configurations = {
1451 pidConfigurationIface, pidZoneConfigurationIface,
1452 stepwiseConfigurationIface};
1453
1454 for (const auto& [path, object] : mObj)
1455 {
1456 for (const auto& [interface, _] : object)
James Feiste69d9de2020-02-07 12:23:27 -08001457 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001458 if (std::ranges::find(configurations, interface) !=
1459 configurations.end())
1460 {
1461 self->objectCount++;
1462 break;
1463 }
James Feiste69d9de2020-02-07 12:23:27 -08001464 }
James Feiste69d9de2020-02-07 12:23:27 -08001465 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001466 self->managedObj = mObj;
1467 });
James Feist73df0db2019-03-25 15:29:35 -07001468
1469 // at the same time get the profile information
George Liue99073f2022-12-09 11:06:16 +08001470 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1471 thermalModeIface};
1472 dbus::utility::getSubTree(
1473 "/", 0, thermalModeIfaces,
1474 [self](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001475 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001476 if (ec || subtree.empty())
James Feist73df0db2019-03-25 15:29:35 -07001477 {
James Feist73df0db2019-03-25 15:29:35 -07001478 return;
1479 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001480 if (subtree[0].second.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001481 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001482 // invalid mapper response, should never happen
1483 BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001484 messages::internalError(self->asyncResp->res);
1485 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001486 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001487
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001488 const std::string& path = subtree[0].first;
1489 const std::string& owner = subtree[0].second[0].first;
1490 sdbusplus::asio::getAllProperties(
1491 *crow::connections::systemBus, owner, path,
1492 thermalModeIface,
1493 [self, path,
1494 owner](const boost::system::error_code& ec2,
1495 const dbus::utility::DBusPropertiesMap& r) {
1496 if (ec2)
1497 {
1498 BMCWEB_LOG_ERROR(
1499 "SetPIDValues: Can't get thermalModeIface {}",
1500 path);
1501 messages::internalError(self->asyncResp->res);
1502 return;
1503 }
1504 const std::string* current = nullptr;
1505 const std::vector<std::string>* supported = nullptr;
1506
1507 const bool success = sdbusplus::unpackPropertiesNoThrow(
1508 dbus_utils::UnpackErrorPrinter(), r, "Current",
1509 current, "Supported", supported);
1510
1511 if (!success)
1512 {
1513 messages::internalError(self->asyncResp->res);
1514 return;
1515 }
1516
1517 if (current == nullptr || supported == nullptr)
1518 {
1519 BMCWEB_LOG_ERROR(
1520 "SetPIDValues: thermal mode iface invalid {}",
1521 path);
1522 messages::internalError(self->asyncResp->res);
1523 return;
1524 }
1525 self->currentProfile = *current;
1526 self->supportedProfiles = *supported;
1527 self->profileConnection = owner;
1528 self->profilePath = path;
1529 });
George Liue99073f2022-12-09 11:06:16 +08001530 });
James Feist73df0db2019-03-25 15:29:35 -07001531 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001532 void pidSetDone()
James Feist73df0db2019-03-25 15:29:35 -07001533 {
1534 if (asyncResp->res.result() != boost::beast::http::status::ok)
1535 {
1536 return;
1537 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001538 std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
James Feist73df0db2019-03-25 15:29:35 -07001539 if (profile)
1540 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07001541 if (std::ranges::find(supportedProfiles, *profile) ==
1542 supportedProfiles.end())
James Feist73df0db2019-03-25 15:29:35 -07001543 {
1544 messages::actionParameterUnknown(response->res, "Profile",
1545 *profile);
1546 return;
1547 }
1548 currentProfile = *profile;
George Liu9ae226f2023-06-21 17:56:46 +08001549 sdbusplus::asio::setProperty(
1550 *crow::connections::systemBus, profileConnection, profilePath,
1551 thermalModeIface, "Current", *profile,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001552 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001553 if (ec)
1554 {
1555 BMCWEB_LOG_ERROR("Error patching profile{}", ec);
1556 messages::internalError(response->res);
1557 }
1558 });
James Feist73df0db2019-03-25 15:29:35 -07001559 }
1560
1561 for (auto& containerPair : configuration)
1562 {
1563 auto& container = containerPair.second;
1564 if (!container)
1565 {
1566 continue;
1567 }
James Feist6ee7f772020-02-06 16:25:27 -08001568
Ed Tanous02cad962022-06-30 16:50:15 -07001569 const std::string& type = containerPair.first;
James Feist73df0db2019-03-25 15:29:35 -07001570
Ed Tanous9e9b6042024-03-06 14:18:28 -08001571 for (auto& [name, value] : *container)
James Feist73df0db2019-03-25 15:29:35 -07001572 {
Potin Laicddbf3d2023-02-14 14:28:58 +08001573 std::string dbusObjName = name;
1574 std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
Ed Tanous62598e32023-07-17 17:06:25 -07001575 BMCWEB_LOG_DEBUG("looking for {}", name);
James Feist6ee7f772020-02-06 16:25:27 -08001576
Ed Tanous3544d2a2023-08-06 18:12:20 -07001577 auto pathItr = std::ranges::find_if(
1578 managedObj, [&dbusObjName](const auto& obj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001579 return obj.first.filename() == dbusObjName;
1580 });
Ed Tanousb9d36b42022-02-26 21:42:46 -08001581 dbus::utility::DBusPropertiesMap output;
James Feist73df0db2019-03-25 15:29:35 -07001582
1583 output.reserve(16); // The pid interface length
1584
1585 // determines if we're patching entity-manager or
1586 // creating a new object
1587 bool createNewObject = (pathItr == managedObj.end());
Ed Tanous62598e32023-07-17 17:06:25 -07001588 BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
James Feist6ee7f772020-02-06 16:25:27 -08001589
James Feist73df0db2019-03-25 15:29:35 -07001590 std::string iface;
Ed Tanousea2b6702022-03-07 16:48:38 -08001591 if (!createNewObject)
James Feist73df0db2019-03-25 15:29:35 -07001592 {
Potin Lai8be2b5b2022-11-22 13:27:16 +08001593 bool findInterface = false;
Ed Tanousea2b6702022-03-07 16:48:38 -08001594 for (const auto& interface : pathItr->second)
James Feist73df0db2019-03-25 15:29:35 -07001595 {
Ed Tanousea2b6702022-03-07 16:48:38 -08001596 if (interface.first == pidConfigurationIface)
1597 {
1598 if (type == "PidControllers" ||
1599 type == "FanControllers")
1600 {
1601 iface = pidConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001602 findInterface = true;
1603 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001604 }
1605 }
1606 else if (interface.first == pidZoneConfigurationIface)
1607 {
1608 if (type == "FanZones")
1609 {
PavanKumarIntelda393502024-03-15 05:47:02 +00001610 iface = pidZoneConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001611 findInterface = true;
1612 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001613 }
1614 }
1615 else if (interface.first == stepwiseConfigurationIface)
1616 {
1617 if (type == "StepwiseControllers")
1618 {
1619 iface = stepwiseConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001620 findInterface = true;
1621 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001622 }
1623 }
James Feist73df0db2019-03-25 15:29:35 -07001624 }
Potin Lai8be2b5b2022-11-22 13:27:16 +08001625
1626 // create new object if interface not found
1627 if (!findInterface)
1628 {
1629 createNewObject = true;
1630 }
James Feist73df0db2019-03-25 15:29:35 -07001631 }
James Feist6ee7f772020-02-06 16:25:27 -08001632
Ed Tanous9e9b6042024-03-06 14:18:28 -08001633 if (createNewObject && value == nullptr)
James Feist6ee7f772020-02-06 16:25:27 -08001634 {
Gunnar Mills4e0453b2020-07-08 14:00:30 -05001635 // can't delete a non-existent object
Ed Tanous9e9b6042024-03-06 14:18:28 -08001636 messages::propertyValueNotInList(response->res, value,
Ed Tanouse2616cc2022-06-27 12:45:55 -07001637 name);
James Feist6ee7f772020-02-06 16:25:27 -08001638 continue;
1639 }
1640
1641 std::string path;
1642 if (pathItr != managedObj.end())
1643 {
1644 path = pathItr->first.str;
1645 }
1646
Ed Tanous62598e32023-07-17 17:06:25 -07001647 BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
James Feiste69d9de2020-02-07 12:23:27 -08001648
1649 // arbitrary limit to avoid attacks
1650 constexpr const size_t controllerLimit = 500;
James Feist14b0b8d2020-02-12 11:52:07 -08001651 if (createNewObject && objectCount >= controllerLimit)
James Feiste69d9de2020-02-07 12:23:27 -08001652 {
1653 messages::resourceExhaustion(response->res, type);
1654 continue;
1655 }
Ed Tanousa170f272022-06-30 21:53:27 -07001656 std::string escaped = name;
1657 std::replace(escaped.begin(), escaped.end(), '_', ' ');
1658 output.emplace_back("Name", escaped);
James Feist73df0db2019-03-25 15:29:35 -07001659
1660 std::string chassis;
1661 CreatePIDRet ret = createPidInterface(
Ed Tanous9e9b6042024-03-06 14:18:28 -08001662 response, type, name, value, path, managedObj,
1663 createNewObject, output, chassis, currentProfile);
James Feist73df0db2019-03-25 15:29:35 -07001664 if (ret == CreatePIDRet::fail)
1665 {
1666 return;
1667 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001668 if (ret == CreatePIDRet::del)
James Feist73df0db2019-03-25 15:29:35 -07001669 {
1670 continue;
1671 }
1672
1673 if (!createNewObject)
1674 {
1675 for (const auto& property : output)
1676 {
Potin Lai7a696972023-11-09 12:18:20 +08001677 crow::connections::systemBus->async_method_call(
James Feist73df0db2019-03-25 15:29:35 -07001678 [response,
1679 propertyName{std::string(property.first)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001680 const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001681 if (ec)
1682 {
1683 BMCWEB_LOG_ERROR("Error patching {}: {}",
1684 propertyName, ec);
1685 messages::internalError(response->res);
1686 return;
1687 }
1688 messages::success(response->res);
1689 },
Potin Lai7a696972023-11-09 12:18:20 +08001690 "xyz.openbmc_project.EntityManager", path,
1691 "org.freedesktop.DBus.Properties", "Set", iface,
1692 property.first, property.second);
James Feist73df0db2019-03-25 15:29:35 -07001693 }
1694 }
1695 else
1696 {
1697 if (chassis.empty())
1698 {
Ed Tanous62598e32023-07-17 17:06:25 -07001699 BMCWEB_LOG_ERROR("Failed to get chassis from config");
Ed Tanousace85d62021-10-26 12:45:59 -07001700 messages::internalError(response->res);
James Feist73df0db2019-03-25 15:29:35 -07001701 return;
1702 }
1703
1704 bool foundChassis = false;
1705 for (const auto& obj : managedObj)
1706 {
Ed Tanous91f75ca2024-06-10 13:56:43 -07001707 if (obj.first.filename() == chassis)
James Feist73df0db2019-03-25 15:29:35 -07001708 {
1709 chassis = obj.first.str;
1710 foundChassis = true;
1711 break;
1712 }
1713 }
1714 if (!foundChassis)
1715 {
Ed Tanous62598e32023-07-17 17:06:25 -07001716 BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
James Feist73df0db2019-03-25 15:29:35 -07001717 messages::resourceMissingAtURI(
Ed Tanousace85d62021-10-26 12:45:59 -07001718 response->res,
Ed Tanousef4c65b2023-04-24 15:28:50 -07001719 boost::urls::format("/redfish/v1/Chassis/{}",
1720 chassis));
James Feist73df0db2019-03-25 15:29:35 -07001721 return;
1722 }
1723
1724 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001725 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001726 if (ec)
1727 {
1728 BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
1729 ec);
1730 messages::internalError(response->res);
1731 return;
1732 }
1733 messages::success(response->res);
1734 },
James Feist73df0db2019-03-25 15:29:35 -07001735 "xyz.openbmc_project.EntityManager", chassis,
1736 "xyz.openbmc_project.AddObject", "AddObject", output);
1737 }
1738 }
1739 }
1740 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001741
1742 ~SetPIDValues()
1743 {
1744 try
1745 {
1746 pidSetDone();
1747 }
1748 catch (...)
1749 {
Ed Tanous62598e32023-07-17 17:06:25 -07001750 BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -08001751 }
1752 }
1753
zhanghch058d1b46d2021-04-01 11:18:24 +08001754 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous9e9b6042024-03-06 14:18:28 -08001755 std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
James Feist73df0db2019-03-25 15:29:35 -07001756 configuration;
1757 std::optional<std::string> profile;
1758 dbus::utility::ManagedObjectType managedObj;
1759 std::vector<std::string> supportedProfiles;
1760 std::string currentProfile;
1761 std::string profileConnection;
1762 std::string profilePath;
James Feist14b0b8d2020-02-12 11:52:07 -08001763 size_t objectCount = 0;
James Feist73df0db2019-03-25 15:29:35 -07001764};
James Feist83ff9ab2018-08-31 10:18:24 -07001765
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001766/**
1767 * @brief Retrieves BMC manager location data over DBus
1768 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001769 * @param[in] asyncResp Shared pointer for completing asynchronous calls
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001770 * @param[in] connectionName - service name
1771 * @param[in] path - object path
1772 * @return none
1773 */
Ed Tanousac106bf2023-06-07 09:24:59 -07001774inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001775 const std::string& connectionName,
1776 const std::string& path)
1777{
Ed Tanous62598e32023-07-17 17:06:25 -07001778 BMCWEB_LOG_DEBUG("Get BMC manager Location data.");
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001779
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001780 sdbusplus::asio::getProperty<std::string>(
1781 *crow::connections::systemBus, connectionName, path,
1782 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanousac106bf2023-06-07 09:24:59 -07001783 [asyncResp](const boost::system::error_code& ec,
1784 const std::string& property) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001785 if (ec)
1786 {
1787 BMCWEB_LOG_DEBUG("DBUS response error for "
1788 "Location");
1789 messages::internalError(asyncResp->res);
1790 return;
1791 }
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001792
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001793 asyncResp->res
1794 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
1795 property;
1796 });
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001797}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001798// avoid name collision systems.hpp
1799inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001800 managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801{
Ed Tanous62598e32023-07-17 17:06:25 -07001802 BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time");
Ed Tanous52cc1122020-07-18 13:51:21 -07001803
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001804 sdbusplus::asio::getProperty<uint64_t>(
1805 *crow::connections::systemBus, "xyz.openbmc_project.State.BMC",
1806 "/xyz/openbmc_project/state/bmc0", "xyz.openbmc_project.State.BMC",
1807 "LastRebootTime",
Ed Tanousac106bf2023-06-07 09:24:59 -07001808 [asyncResp](const boost::system::error_code& ec,
1809 const uint64_t lastResetTime) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001810 if (ec)
1811 {
1812 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1813 return;
1814 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001815
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001816 // LastRebootTime is epoch time, in milliseconds
1817 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
1818 uint64_t lastResetTimeStamp = lastResetTime / 1000;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001819
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001820 // Convert to ISO 8601 standard
1821 asyncResp->res.jsonValue["LastResetTime"] =
1822 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1823 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001824}
1825
1826/**
1827 * @brief Set the running firmware image
1828 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001829 * @param[i,o] asyncResp - Async response object
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001830 * @param[i] runningFirmwareTarget - Image to make the running image
1831 *
1832 * @return void
1833 */
1834inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001835 setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001836 const std::string& runningFirmwareTarget)
1837{
1838 // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1839 std::string::size_type idPos = runningFirmwareTarget.rfind('/');
1840 if (idPos == std::string::npos)
1841 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001842 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001843 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001844 BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001845 return;
1846 }
1847 idPos++;
1848 if (idPos >= runningFirmwareTarget.size())
1849 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001850 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001851 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001852 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001853 return;
1854 }
1855 std::string firmwareId = runningFirmwareTarget.substr(idPos);
1856
1857 // Make sure the image is valid before setting priority
George Liu5eb468d2023-06-20 17:03:24 +08001858 sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
1859 dbus::utility::getManagedObjects(
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -07001860 getBMCUpdateServiceName(), objPath,
George Liu5eb468d2023-06-20 17:03:24 +08001861 [asyncResp, firmwareId, runningFirmwareTarget](
1862 const boost::system::error_code& ec,
1863 const dbus::utility::ManagedObjectType& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001864 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001865 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001866 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
Ed Tanousac106bf2023-06-07 09:24:59 -07001867 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001868 return;
1869 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001870
1871 if (subtree.empty())
1872 {
1873 BMCWEB_LOG_DEBUG("Can't find image!");
1874 messages::internalError(asyncResp->res);
1875 return;
1876 }
1877
1878 bool foundImage = false;
1879 for (const auto& object : subtree)
1880 {
1881 const std::string& path =
1882 static_cast<const std::string&>(object.first);
1883 std::size_t idPos2 = path.rfind('/');
1884
1885 if (idPos2 == std::string::npos)
1886 {
1887 continue;
1888 }
1889
1890 idPos2++;
1891 if (idPos2 >= path.size())
1892 {
1893 continue;
1894 }
1895
1896 if (path.substr(idPos2) == firmwareId)
1897 {
1898 foundImage = true;
1899 break;
1900 }
1901 }
1902
1903 if (!foundImage)
1904 {
1905 messages::propertyValueNotInList(
1906 asyncResp->res, runningFirmwareTarget, "@odata.id");
1907 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
1908 return;
1909 }
1910
1911 BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
1912 firmwareId);
1913
1914 // Only support Immediate
1915 // An addition could be a Redfish Setting like
1916 // ActiveSoftwareImageApplyTime and support OnReset
1917 sdbusplus::asio::setProperty(
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -07001918 *crow::connections::systemBus, getBMCUpdateServiceName(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001919 "/xyz/openbmc_project/software/" + firmwareId,
1920 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
1921 static_cast<uint8_t>(0),
1922 [asyncResp](const boost::system::error_code& ec2) {
1923 if (ec2)
1924 {
1925 BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1926 messages::internalError(asyncResp->res);
1927 return;
1928 }
1929 doBMCGracefulRestart(asyncResp);
1930 });
George Liu5eb468d2023-06-20 17:03:24 +08001931 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001932}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001933
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001934inline void afterSetDateTime(
1935 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1936 const boost::system::error_code& ec, const sdbusplus::message_t& msg)
Ed Tanousc51afd52024-03-07 10:13:14 -08001937{
1938 if (ec)
1939 {
1940 BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1941 ec);
1942 const sd_bus_error* dbusError = msg.get_error();
1943 if (dbusError != nullptr)
1944 {
1945 std::string_view errorName(dbusError->name);
1946 if (errorName ==
1947 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1948 {
1949 BMCWEB_LOG_DEBUG("Setting conflict");
1950 messages::propertyValueConflict(
1951 asyncResp->res, "DateTime",
1952 "Managers/NetworkProtocol/NTPProcotolEnabled");
1953 return;
1954 }
1955 }
1956 messages::internalError(asyncResp->res);
1957 return;
1958 }
1959 asyncResp->res.result(boost::beast::http::status::no_content);
1960}
1961
1962inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1963 const std::string& datetime)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001964{
Ed Tanous62598e32023-07-17 17:06:25 -07001965 BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001966
Ed Tanousc2e32002023-01-07 22:05:08 -08001967 std::optional<redfish::time_utils::usSinceEpoch> us =
1968 redfish::time_utils::dateStringToEpoch(datetime);
1969 if (!us)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001970 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001971 messages::propertyValueFormatError(asyncResp->res, datetime,
1972 "DateTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001973 return;
1974 }
Ed Tanousc51afd52024-03-07 10:13:14 -08001975 // Set the absolute datetime
1976 bool relative = false;
1977 bool interactive = false;
1978 crow::connections::systemBus->async_method_call(
1979 [asyncResp](const boost::system::error_code& ec,
1980 const sdbusplus::message_t& msg) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001981 afterSetDateTime(asyncResp, ec, msg);
1982 },
Ed Tanousc51afd52024-03-07 10:13:14 -08001983 "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1984 "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1985 interactive);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001986}
1987
Ed Tanous75815e52022-10-05 17:21:13 -07001988inline void
1989 checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1990{
1991 sdbusplus::asio::getProperty<std::string>(
1992 *crow::connections::systemBus, "org.freedesktop.systemd1",
1993 "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
1994 "org.freedesktop.systemd1.Unit", "ActiveState",
1995 [asyncResp](const boost::system::error_code& ec,
1996 const std::string& val) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001997 if (!ec)
Ed Tanous75815e52022-10-05 17:21:13 -07001998 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001999 if (val == "active")
2000 {
2001 asyncResp->res.jsonValue["Status"]["Health"] =
2002 resource::Health::Critical;
2003 asyncResp->res.jsonValue["Status"]["State"] =
2004 resource::State::Quiesced;
2005 return;
2006 }
Ed Tanous75815e52022-10-05 17:21:13 -07002007 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002008 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
2009 asyncResp->res.jsonValue["Status"]["State"] =
2010 resource::State::Enabled;
2011 });
Ed Tanous75815e52022-10-05 17:21:13 -07002012}
2013
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002014inline void requestRoutesManager(App& app)
2015{
2016 std::string uuid = persistent_data::getConfig().systemUuid;
2017
Ed Tanous253f11b2024-05-16 09:38:31 -07002018 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002019 .privileges(redfish::privileges::getManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002020 .methods(
2021 boost::beast::http::verb::
2022 get)([&app,
2023 uuid](const crow::Request& req,
2024 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2025 const std::string& managerId) {
2026 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2027 {
2028 return;
2029 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002030
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002031 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2032 {
2033 messages::resourceNotFound(asyncResp->res, "Manager",
2034 managerId);
2035 return;
2036 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002037
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002038 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2039 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2040 asyncResp->res.jsonValue["@odata.type"] =
2041 "#Manager.v1_14_0.Manager";
2042 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
2043 asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
2044 asyncResp->res.jsonValue["Description"] =
2045 "Baseboard Management Controller";
2046 asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
Ed Tanous14766872022-03-15 10:44:42 -07002047
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002048 asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
2049 asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
2050 asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2051 asyncResp->res.jsonValue["Model"] =
2052 "OpenBmc"; // TODO(ed), get model
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002053
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002054 asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2055 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
Ed Tanous253f11b2024-05-16 09:38:31 -07002056 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002057 asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2058 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2059 BMCWEB_REDFISH_MANAGER_URI_NAME);
2060 asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2061 boost::urls::format(
2062 "/redfish/v1/Managers/{}/EthernetInterfaces",
2063 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002064
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002065 if constexpr (BMCWEB_VM_NBDPROXY)
Ed Tanous75815e52022-10-05 17:21:13 -07002066 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002067 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2068 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2069 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002070 }
2071
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002072 // default oem data
2073 nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
2074 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2075 oem["@odata.id"] =
2076 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2077 BMCWEB_REDFISH_MANAGER_URI_NAME);
2078 oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2079 oemOpenbmc["@odata.id"] =
2080 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2081 BMCWEB_REDFISH_MANAGER_URI_NAME);
2082
2083 nlohmann::json::object_t certificates;
2084 certificates["@odata.id"] = boost::urls::format(
2085 "/redfish/v1/Managers/{}/Truststore/Certificates",
2086 BMCWEB_REDFISH_MANAGER_URI_NAME);
2087 oemOpenbmc["Certificates"] = std::move(certificates);
2088
2089 // Manager.Reset (an action) can be many values, OpenBMC only
2090 // supports BMC reboot.
2091 nlohmann::json& managerReset =
2092 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2093 managerReset["target"] = boost::urls::format(
2094 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2095 BMCWEB_REDFISH_MANAGER_URI_NAME);
2096 managerReset["@Redfish.ActionInfo"] =
2097 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2098 BMCWEB_REDFISH_MANAGER_URI_NAME);
2099
2100 // ResetToDefaults (Factory Reset) has values like
2101 // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
2102 // on OpenBMC
2103 nlohmann::json& resetToDefaults =
2104 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2105 resetToDefaults["target"] = boost::urls::format(
2106 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2107 BMCWEB_REDFISH_MANAGER_URI_NAME);
2108 resetToDefaults["ResetType@Redfish.AllowableValues"] =
2109 nlohmann::json::array_t({"ResetAll"});
2110
2111 std::pair<std::string, std::string> redfishDateTimeOffset =
2112 redfish::time_utils::getDateTimeOffsetNow();
2113
2114 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2115 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2116 redfishDateTimeOffset.second;
2117
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002118 if constexpr (BMCWEB_KVM)
Ed Tanous002d39b2022-05-31 08:59:27 -07002119 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002120 // Fill in GraphicalConsole info
2121 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
2122 true;
2123 asyncResp->res
2124 .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
2125 asyncResp->res
2126 .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2127 nlohmann::json::array_t({"KVMIP"});
2128 }
2129 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2130 {
2131 asyncResp->res
2132 .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
2133
2134 nlohmann::json::array_t managerForServers;
2135 nlohmann::json::object_t manager;
2136 manager["@odata.id"] = std::format(
2137 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2138 managerForServers.emplace_back(std::move(manager));
2139
2140 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
2141 std::move(managerForServers);
Ed Tanous002d39b2022-05-31 08:59:27 -07002142 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002143
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002144 sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
2145 "FirmwareVersion", true);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002146
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002147 managerGetLastResetTime(asyncResp);
2148
2149 // ManagerDiagnosticData is added for all BMCs.
2150 nlohmann::json& managerDiagnosticData =
2151 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2152 managerDiagnosticData["@odata.id"] = boost::urls::format(
2153 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2154 BMCWEB_REDFISH_MANAGER_URI_NAME);
2155
2156 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
Ed Tanous002d39b2022-05-31 08:59:27 -07002157 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002158 auto pids = std::make_shared<GetPIDValues>(asyncResp);
2159 pids->run();
2160 }
2161
2162 getMainChassisId(asyncResp, [](const std::string& chassisId,
2163 const std::shared_ptr<
2164 bmcweb::AsyncResp>& aRsp) {
2165 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2166 1;
2167 nlohmann::json::array_t managerForChassis;
2168 nlohmann::json::object_t managerObj;
2169 boost::urls::url chassiUrl =
2170 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2171 managerObj["@odata.id"] = chassiUrl;
2172 managerForChassis.emplace_back(std::move(managerObj));
2173 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
2174 std::move(managerForChassis);
2175 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2176 chassiUrl;
2177 });
2178
2179 sdbusplus::asio::getProperty<double>(
2180 *crow::connections::systemBus, "org.freedesktop.systemd1",
2181 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
2182 "Progress",
2183 [asyncResp](const boost::system::error_code& ec, double val) {
2184 if (ec)
2185 {
2186 BMCWEB_LOG_ERROR("Error while getting progress");
2187 messages::internalError(asyncResp->res);
2188 return;
2189 }
2190 if (val < 1.0)
2191 {
2192 asyncResp->res.jsonValue["Status"]["Health"] =
2193 resource::Health::OK;
2194 asyncResp->res.jsonValue["Status"]["State"] =
2195 resource::State::Starting;
2196 return;
2197 }
2198 checkForQuiesced(asyncResp);
2199 });
2200
2201 constexpr std::array<std::string_view, 1> interfaces = {
2202 "xyz.openbmc_project.Inventory.Item.Bmc"};
2203 dbus::utility::getSubTree(
2204 "/xyz/openbmc_project/inventory", 0, interfaces,
2205 [asyncResp](
2206 const boost::system::error_code& ec,
2207 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2208 if (ec)
2209 {
2210 BMCWEB_LOG_DEBUG(
2211 "D-Bus response error on GetSubTree {}", ec);
2212 return;
2213 }
2214 if (subtree.empty())
2215 {
2216 BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
2217 return;
2218 }
2219 // Assume only 1 bmc D-Bus object
2220 // Throw an error if there is more than 1
2221 if (subtree.size() > 1)
2222 {
2223 BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
2224 messages::internalError(asyncResp->res);
2225 return;
2226 }
2227
2228 if (subtree[0].first.empty() ||
2229 subtree[0].second.size() != 1)
2230 {
2231 BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
2232 messages::internalError(asyncResp->res);
2233 return;
2234 }
2235
2236 const std::string& path = subtree[0].first;
2237 const std::string& connectionName =
2238 subtree[0].second[0].first;
2239
2240 for (const auto& interfaceName :
2241 subtree[0].second[0].second)
2242 {
2243 if (interfaceName ==
2244 "xyz.openbmc_project.Inventory.Decorator.Asset")
2245 {
2246 sdbusplus::asio::getAllProperties(
2247 *crow::connections::systemBus, connectionName,
2248 path,
2249 "xyz.openbmc_project.Inventory.Decorator.Asset",
2250 [asyncResp](
2251 const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002252 const dbus::utility::DBusPropertiesMap&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002253 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002254 if (ec2)
2255 {
2256 BMCWEB_LOG_DEBUG(
2257 "Can't get bmc asset!");
2258 return;
2259 }
2260
2261 const std::string* partNumber = nullptr;
2262 const std::string* serialNumber = nullptr;
2263 const std::string* manufacturer = nullptr;
2264 const std::string* model = nullptr;
2265 const std::string* sparePartNumber =
2266 nullptr;
2267
2268 const bool success =
2269 sdbusplus::unpackPropertiesNoThrow(
2270 dbus_utils::UnpackErrorPrinter(),
2271 propertiesList, "PartNumber",
2272 partNumber, "SerialNumber",
2273 serialNumber, "Manufacturer",
2274 manufacturer, "Model", model,
2275 "SparePartNumber", sparePartNumber);
2276
2277 if (!success)
2278 {
2279 messages::internalError(asyncResp->res);
2280 return;
2281 }
2282
2283 if (partNumber != nullptr)
2284 {
2285 asyncResp->res.jsonValue["PartNumber"] =
2286 *partNumber;
2287 }
2288
2289 if (serialNumber != nullptr)
2290 {
2291 asyncResp->res
2292 .jsonValue["SerialNumber"] =
2293 *serialNumber;
2294 }
2295
2296 if (manufacturer != nullptr)
2297 {
2298 asyncResp->res
2299 .jsonValue["Manufacturer"] =
2300 *manufacturer;
2301 }
2302
2303 if (model != nullptr)
2304 {
2305 asyncResp->res.jsonValue["Model"] =
2306 *model;
2307 }
2308
2309 if (sparePartNumber != nullptr)
2310 {
2311 asyncResp->res
2312 .jsonValue["SparePartNumber"] =
2313 *sparePartNumber;
2314 }
2315 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002316 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002317 else if (
2318 interfaceName ==
2319 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02002320 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002321 getLocation(asyncResp, connectionName, path);
Ed Tanous002d39b2022-05-31 08:59:27 -07002322 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002323 }
2324 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002325 });
2326
Ed Tanous253f11b2024-05-16 09:38:31 -07002327 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002328 .privileges(redfish::privileges::patchManager)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002329 .methods(boost::beast::http::verb::patch)(
2330 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002331 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2332 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002333 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2334 {
2335 return;
2336 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002337
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002338 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2339 {
2340 messages::resourceNotFound(asyncResp->res, "Manager",
2341 managerId);
2342 return;
2343 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002344
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002345 std::optional<std::string> activeSoftwareImageOdataId;
2346 std::optional<std::string> datetime;
2347 std::optional<nlohmann::json::object_t> pidControllers;
2348 std::optional<nlohmann::json::object_t> fanControllers;
2349 std::optional<nlohmann::json::object_t> fanZones;
2350 std::optional<nlohmann::json::object_t> stepwiseControllers;
2351 std::optional<std::string> profile;
Ed Tanous002d39b2022-05-31 08:59:27 -07002352
Myung Baeafc474a2024-10-09 00:53:29 -07002353 if (!json_util::readJsonPatch( //
2354 req, asyncResp->res, //
2355 "DateTime", datetime, //
2356 "Links/ActiveSoftwareImage/@odata.id",
2357 activeSoftwareImageOdataId, //
2358 "Oem/OpenBmc/Fan/FanControllers", fanControllers, //
2359 "Oem/OpenBmc/Fan/FanZones", fanZones, //
2360 "Oem/OpenBmc/Fan/PidControllers", pidControllers, //
2361 "Oem/OpenBmc/Fan/Profile", profile, //
2362 "Oem/OpenBmc/Fan/StepwiseControllers",
2363 stepwiseControllers //
2364 ))
2365 {
2366 return;
2367 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002368
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002369 if (pidControllers || fanControllers || fanZones ||
2370 stepwiseControllers || profile)
2371 {
2372 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
2373 {
2374 std::vector<
2375 std::pair<std::string,
Ed Tanous25b54db2024-04-17 15:40:31 -07002376 std::optional<nlohmann::json::object_t>>>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002377 configuration;
2378 if (pidControllers)
2379 {
2380 configuration.emplace_back(
2381 "PidControllers", std::move(pidControllers));
2382 }
2383 if (fanControllers)
2384 {
2385 configuration.emplace_back(
2386 "FanControllers", std::move(fanControllers));
2387 }
2388 if (fanZones)
2389 {
2390 configuration.emplace_back("FanZones",
2391 std::move(fanZones));
2392 }
2393 if (stepwiseControllers)
2394 {
2395 configuration.emplace_back(
2396 "StepwiseControllers",
2397 std::move(stepwiseControllers));
2398 }
2399 auto pid = std::make_shared<SetPIDValues>(
2400 asyncResp, std::move(configuration), profile);
2401 pid->run();
2402 }
2403 else
2404 {
2405 messages::propertyUnknown(asyncResp->res, "Oem");
2406 return;
2407 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002408 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002409
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002410 if (activeSoftwareImageOdataId)
2411 {
2412 setActiveFirmwareImage(asyncResp,
2413 *activeSoftwareImageOdataId);
2414 }
Ed Tanous9e9b6042024-03-06 14:18:28 -08002415
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002416 if (datetime)
2417 {
2418 setDateTime(asyncResp, *datetime);
2419 }
2420 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002421}
2422
2423inline void requestRoutesManagerCollection(App& app)
2424{
2425 BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
Ed Tanoused398212021-06-09 17:05:54 -07002426 .privileges(redfish::privileges::getManagerCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002427 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002428 [&app](const crow::Request& req,
2429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002430 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2431 {
2432 return;
2433 }
2434 // Collections don't include the static data added by SubRoute
2435 // because it has a duplicate entry for members
2436 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
2437 asyncResp->res.jsonValue["@odata.type"] =
2438 "#ManagerCollection.ManagerCollection";
2439 asyncResp->res.jsonValue["Name"] = "Manager Collection";
2440 asyncResp->res.jsonValue["Members@odata.count"] = 1;
2441 nlohmann::json::array_t members;
2442 nlohmann::json& bmc = members.emplace_back();
2443 bmc["@odata.id"] = boost::urls::format(
2444 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2445 asyncResp->res.jsonValue["Members"] = std::move(members);
2446 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002447}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002448} // namespace redfish