blob: 2f21656b87e0470d8554cfae40f2bdfd233bb014 [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
Ed Tanousdeae6a72024-11-11 21:58:57 -08001292 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001293 *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;
Ed Tanousdeae6a72024-11-11 21:58:57 -08001490 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001491 *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
Ed Tanousdeae6a72024-11-11 21:58:57 -08001780 dbus::utility::getProperty<std::string>(
1781 connectionName, path,
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001782 "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
Ed Tanousdeae6a72024-11-11 21:58:57 -08001804 dbus::utility::getProperty<uint64_t>(
1805 "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
1806 "xyz.openbmc_project.State.BMC", "LastRebootTime",
Ed Tanousac106bf2023-06-07 09:24:59 -07001807 [asyncResp](const boost::system::error_code& ec,
1808 const uint64_t lastResetTime) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001809 if (ec)
1810 {
1811 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1812 return;
1813 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001814
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001815 // LastRebootTime is epoch time, in milliseconds
1816 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
1817 uint64_t lastResetTimeStamp = lastResetTime / 1000;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001818
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001819 // Convert to ISO 8601 standard
1820 asyncResp->res.jsonValue["LastResetTime"] =
1821 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1822 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001823}
1824
1825/**
1826 * @brief Set the running firmware image
1827 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001828 * @param[i,o] asyncResp - Async response object
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001829 * @param[i] runningFirmwareTarget - Image to make the running image
1830 *
1831 * @return void
1832 */
1833inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001834 setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001835 const std::string& runningFirmwareTarget)
1836{
1837 // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1838 std::string::size_type idPos = runningFirmwareTarget.rfind('/');
1839 if (idPos == std::string::npos)
1840 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001841 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001842 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001843 BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001844 return;
1845 }
1846 idPos++;
1847 if (idPos >= runningFirmwareTarget.size())
1848 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001849 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001850 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001851 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001852 return;
1853 }
1854 std::string firmwareId = runningFirmwareTarget.substr(idPos);
1855
1856 // Make sure the image is valid before setting priority
George Liu5eb468d2023-06-20 17:03:24 +08001857 sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
1858 dbus::utility::getManagedObjects(
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -07001859 getBMCUpdateServiceName(), objPath,
George Liu5eb468d2023-06-20 17:03:24 +08001860 [asyncResp, firmwareId, runningFirmwareTarget](
1861 const boost::system::error_code& ec,
1862 const dbus::utility::ManagedObjectType& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001863 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001864 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001865 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
Ed Tanousac106bf2023-06-07 09:24:59 -07001866 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001867 return;
1868 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001869
1870 if (subtree.empty())
1871 {
1872 BMCWEB_LOG_DEBUG("Can't find image!");
1873 messages::internalError(asyncResp->res);
1874 return;
1875 }
1876
1877 bool foundImage = false;
1878 for (const auto& object : subtree)
1879 {
1880 const std::string& path =
1881 static_cast<const std::string&>(object.first);
1882 std::size_t idPos2 = path.rfind('/');
1883
1884 if (idPos2 == std::string::npos)
1885 {
1886 continue;
1887 }
1888
1889 idPos2++;
1890 if (idPos2 >= path.size())
1891 {
1892 continue;
1893 }
1894
1895 if (path.substr(idPos2) == firmwareId)
1896 {
1897 foundImage = true;
1898 break;
1899 }
1900 }
1901
1902 if (!foundImage)
1903 {
1904 messages::propertyValueNotInList(
1905 asyncResp->res, runningFirmwareTarget, "@odata.id");
1906 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
1907 return;
1908 }
1909
1910 BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
1911 firmwareId);
1912
1913 // Only support Immediate
1914 // An addition could be a Redfish Setting like
1915 // ActiveSoftwareImageApplyTime and support OnReset
1916 sdbusplus::asio::setProperty(
Jagpal Singh Gilld27c31e2024-10-15 15:10:19 -07001917 *crow::connections::systemBus, getBMCUpdateServiceName(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001918 "/xyz/openbmc_project/software/" + firmwareId,
1919 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
1920 static_cast<uint8_t>(0),
1921 [asyncResp](const boost::system::error_code& ec2) {
1922 if (ec2)
1923 {
1924 BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1925 messages::internalError(asyncResp->res);
1926 return;
1927 }
1928 doBMCGracefulRestart(asyncResp);
1929 });
George Liu5eb468d2023-06-20 17:03:24 +08001930 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001931}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001932
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001933inline void afterSetDateTime(
1934 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1935 const boost::system::error_code& ec, const sdbusplus::message_t& msg)
Ed Tanousc51afd52024-03-07 10:13:14 -08001936{
1937 if (ec)
1938 {
1939 BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1940 ec);
1941 const sd_bus_error* dbusError = msg.get_error();
1942 if (dbusError != nullptr)
1943 {
1944 std::string_view errorName(dbusError->name);
1945 if (errorName ==
1946 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1947 {
1948 BMCWEB_LOG_DEBUG("Setting conflict");
1949 messages::propertyValueConflict(
1950 asyncResp->res, "DateTime",
1951 "Managers/NetworkProtocol/NTPProcotolEnabled");
1952 return;
1953 }
1954 }
1955 messages::internalError(asyncResp->res);
1956 return;
1957 }
1958 asyncResp->res.result(boost::beast::http::status::no_content);
1959}
1960
1961inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1962 const std::string& datetime)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001963{
Ed Tanous62598e32023-07-17 17:06:25 -07001964 BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001965
Ed Tanousc2e32002023-01-07 22:05:08 -08001966 std::optional<redfish::time_utils::usSinceEpoch> us =
1967 redfish::time_utils::dateStringToEpoch(datetime);
1968 if (!us)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001969 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001970 messages::propertyValueFormatError(asyncResp->res, datetime,
1971 "DateTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001972 return;
1973 }
Ed Tanousc51afd52024-03-07 10:13:14 -08001974 // Set the absolute datetime
1975 bool relative = false;
1976 bool interactive = false;
1977 crow::connections::systemBus->async_method_call(
1978 [asyncResp](const boost::system::error_code& ec,
1979 const sdbusplus::message_t& msg) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001980 afterSetDateTime(asyncResp, ec, msg);
1981 },
Ed Tanousc51afd52024-03-07 10:13:14 -08001982 "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1983 "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1984 interactive);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001985}
1986
Ed Tanous75815e52022-10-05 17:21:13 -07001987inline void
1988 checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1989{
Ed Tanousdeae6a72024-11-11 21:58:57 -08001990 dbus::utility::getProperty<std::string>(
1991 "org.freedesktop.systemd1",
Ed Tanous75815e52022-10-05 17:21:13 -07001992 "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
1993 "org.freedesktop.systemd1.Unit", "ActiveState",
1994 [asyncResp](const boost::system::error_code& ec,
1995 const std::string& val) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001996 if (!ec)
Ed Tanous75815e52022-10-05 17:21:13 -07001997 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001998 if (val == "active")
1999 {
2000 asyncResp->res.jsonValue["Status"]["Health"] =
2001 resource::Health::Critical;
2002 asyncResp->res.jsonValue["Status"]["State"] =
2003 resource::State::Quiesced;
2004 return;
2005 }
Ed Tanous75815e52022-10-05 17:21:13 -07002006 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002007 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
2008 asyncResp->res.jsonValue["Status"]["State"] =
2009 resource::State::Enabled;
2010 });
Ed Tanous75815e52022-10-05 17:21:13 -07002011}
2012
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002013inline void requestRoutesManager(App& app)
2014{
2015 std::string uuid = persistent_data::getConfig().systemUuid;
2016
Ed Tanous253f11b2024-05-16 09:38:31 -07002017 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002018 .privileges(redfish::privileges::getManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002019 .methods(
2020 boost::beast::http::verb::
2021 get)([&app,
2022 uuid](const crow::Request& req,
2023 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2024 const std::string& managerId) {
2025 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2026 {
2027 return;
2028 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002029
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002030 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2031 {
2032 messages::resourceNotFound(asyncResp->res, "Manager",
2033 managerId);
2034 return;
2035 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002036
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002037 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2038 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2039 asyncResp->res.jsonValue["@odata.type"] =
2040 "#Manager.v1_14_0.Manager";
2041 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
2042 asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
2043 asyncResp->res.jsonValue["Description"] =
2044 "Baseboard Management Controller";
2045 asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
Ed Tanous14766872022-03-15 10:44:42 -07002046
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002047 asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
2048 asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
2049 asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2050 asyncResp->res.jsonValue["Model"] =
2051 "OpenBmc"; // TODO(ed), get model
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002052
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002053 asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2054 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
Ed Tanous253f11b2024-05-16 09:38:31 -07002055 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002056 asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2057 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2058 BMCWEB_REDFISH_MANAGER_URI_NAME);
2059 asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2060 boost::urls::format(
2061 "/redfish/v1/Managers/{}/EthernetInterfaces",
2062 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002063
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002064 if constexpr (BMCWEB_VM_NBDPROXY)
Ed Tanous75815e52022-10-05 17:21:13 -07002065 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002066 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2067 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2068 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002069 }
2070
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002071 // default oem data
2072 nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
2073 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2074 oem["@odata.id"] =
2075 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2076 BMCWEB_REDFISH_MANAGER_URI_NAME);
2077 oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2078 oemOpenbmc["@odata.id"] =
2079 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2080 BMCWEB_REDFISH_MANAGER_URI_NAME);
2081
2082 nlohmann::json::object_t certificates;
2083 certificates["@odata.id"] = boost::urls::format(
2084 "/redfish/v1/Managers/{}/Truststore/Certificates",
2085 BMCWEB_REDFISH_MANAGER_URI_NAME);
2086 oemOpenbmc["Certificates"] = std::move(certificates);
2087
2088 // Manager.Reset (an action) can be many values, OpenBMC only
2089 // supports BMC reboot.
2090 nlohmann::json& managerReset =
2091 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2092 managerReset["target"] = boost::urls::format(
2093 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2094 BMCWEB_REDFISH_MANAGER_URI_NAME);
2095 managerReset["@Redfish.ActionInfo"] =
2096 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2097 BMCWEB_REDFISH_MANAGER_URI_NAME);
2098
2099 // ResetToDefaults (Factory Reset) has values like
2100 // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
2101 // on OpenBMC
2102 nlohmann::json& resetToDefaults =
2103 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2104 resetToDefaults["target"] = boost::urls::format(
2105 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2106 BMCWEB_REDFISH_MANAGER_URI_NAME);
2107 resetToDefaults["ResetType@Redfish.AllowableValues"] =
2108 nlohmann::json::array_t({"ResetAll"});
2109
2110 std::pair<std::string, std::string> redfishDateTimeOffset =
2111 redfish::time_utils::getDateTimeOffsetNow();
2112
2113 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2114 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2115 redfishDateTimeOffset.second;
2116
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002117 if constexpr (BMCWEB_KVM)
Ed Tanous002d39b2022-05-31 08:59:27 -07002118 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002119 // Fill in GraphicalConsole info
2120 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
2121 true;
2122 asyncResp->res
2123 .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
2124 asyncResp->res
2125 .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2126 nlohmann::json::array_t({"KVMIP"});
2127 }
2128 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2129 {
2130 asyncResp->res
2131 .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
2132
2133 nlohmann::json::array_t managerForServers;
2134 nlohmann::json::object_t manager;
2135 manager["@odata.id"] = std::format(
2136 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2137 managerForServers.emplace_back(std::move(manager));
2138
2139 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
2140 std::move(managerForServers);
Ed Tanous002d39b2022-05-31 08:59:27 -07002141 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002142
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002143 sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
2144 "FirmwareVersion", true);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002145
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002146 managerGetLastResetTime(asyncResp);
2147
2148 // ManagerDiagnosticData is added for all BMCs.
2149 nlohmann::json& managerDiagnosticData =
2150 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2151 managerDiagnosticData["@odata.id"] = boost::urls::format(
2152 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2153 BMCWEB_REDFISH_MANAGER_URI_NAME);
2154
2155 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
Ed Tanous002d39b2022-05-31 08:59:27 -07002156 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002157 auto pids = std::make_shared<GetPIDValues>(asyncResp);
2158 pids->run();
2159 }
2160
2161 getMainChassisId(asyncResp, [](const std::string& chassisId,
2162 const std::shared_ptr<
2163 bmcweb::AsyncResp>& aRsp) {
2164 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2165 1;
2166 nlohmann::json::array_t managerForChassis;
2167 nlohmann::json::object_t managerObj;
2168 boost::urls::url chassiUrl =
2169 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2170 managerObj["@odata.id"] = chassiUrl;
2171 managerForChassis.emplace_back(std::move(managerObj));
2172 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
2173 std::move(managerForChassis);
2174 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2175 chassiUrl;
2176 });
2177
Ed Tanousdeae6a72024-11-11 21:58:57 -08002178 dbus::utility::getProperty<double>(
2179 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
2180 "org.freedesktop.systemd1.Manager", "Progress",
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002181 [asyncResp](const boost::system::error_code& ec, double val) {
2182 if (ec)
2183 {
2184 BMCWEB_LOG_ERROR("Error while getting progress");
2185 messages::internalError(asyncResp->res);
2186 return;
2187 }
2188 if (val < 1.0)
2189 {
2190 asyncResp->res.jsonValue["Status"]["Health"] =
2191 resource::Health::OK;
2192 asyncResp->res.jsonValue["Status"]["State"] =
2193 resource::State::Starting;
2194 return;
2195 }
2196 checkForQuiesced(asyncResp);
2197 });
2198
2199 constexpr std::array<std::string_view, 1> interfaces = {
2200 "xyz.openbmc_project.Inventory.Item.Bmc"};
2201 dbus::utility::getSubTree(
2202 "/xyz/openbmc_project/inventory", 0, interfaces,
2203 [asyncResp](
2204 const boost::system::error_code& ec,
2205 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2206 if (ec)
2207 {
2208 BMCWEB_LOG_DEBUG(
2209 "D-Bus response error on GetSubTree {}", ec);
2210 return;
2211 }
2212 if (subtree.empty())
2213 {
2214 BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
2215 return;
2216 }
2217 // Assume only 1 bmc D-Bus object
2218 // Throw an error if there is more than 1
2219 if (subtree.size() > 1)
2220 {
2221 BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
2222 messages::internalError(asyncResp->res);
2223 return;
2224 }
2225
2226 if (subtree[0].first.empty() ||
2227 subtree[0].second.size() != 1)
2228 {
2229 BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
2230 messages::internalError(asyncResp->res);
2231 return;
2232 }
2233
2234 const std::string& path = subtree[0].first;
2235 const std::string& connectionName =
2236 subtree[0].second[0].first;
2237
2238 for (const auto& interfaceName :
2239 subtree[0].second[0].second)
2240 {
2241 if (interfaceName ==
2242 "xyz.openbmc_project.Inventory.Decorator.Asset")
2243 {
Ed Tanousdeae6a72024-11-11 21:58:57 -08002244 dbus::utility::getAllProperties(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002245 *crow::connections::systemBus, connectionName,
2246 path,
2247 "xyz.openbmc_project.Inventory.Decorator.Asset",
2248 [asyncResp](
2249 const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002250 const dbus::utility::DBusPropertiesMap&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002251 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002252 if (ec2)
2253 {
2254 BMCWEB_LOG_DEBUG(
2255 "Can't get bmc asset!");
2256 return;
2257 }
2258
2259 const std::string* partNumber = nullptr;
2260 const std::string* serialNumber = nullptr;
2261 const std::string* manufacturer = nullptr;
2262 const std::string* model = nullptr;
2263 const std::string* sparePartNumber =
2264 nullptr;
2265
2266 const bool success =
2267 sdbusplus::unpackPropertiesNoThrow(
2268 dbus_utils::UnpackErrorPrinter(),
2269 propertiesList, "PartNumber",
2270 partNumber, "SerialNumber",
2271 serialNumber, "Manufacturer",
2272 manufacturer, "Model", model,
2273 "SparePartNumber", sparePartNumber);
2274
2275 if (!success)
2276 {
2277 messages::internalError(asyncResp->res);
2278 return;
2279 }
2280
2281 if (partNumber != nullptr)
2282 {
2283 asyncResp->res.jsonValue["PartNumber"] =
2284 *partNumber;
2285 }
2286
2287 if (serialNumber != nullptr)
2288 {
2289 asyncResp->res
2290 .jsonValue["SerialNumber"] =
2291 *serialNumber;
2292 }
2293
2294 if (manufacturer != nullptr)
2295 {
2296 asyncResp->res
2297 .jsonValue["Manufacturer"] =
2298 *manufacturer;
2299 }
2300
2301 if (model != nullptr)
2302 {
2303 asyncResp->res.jsonValue["Model"] =
2304 *model;
2305 }
2306
2307 if (sparePartNumber != nullptr)
2308 {
2309 asyncResp->res
2310 .jsonValue["SparePartNumber"] =
2311 *sparePartNumber;
2312 }
2313 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002314 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002315 else if (
2316 interfaceName ==
2317 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02002318 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002319 getLocation(asyncResp, connectionName, path);
Ed Tanous002d39b2022-05-31 08:59:27 -07002320 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002321 }
2322 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002323 });
2324
Ed Tanous253f11b2024-05-16 09:38:31 -07002325 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002326 .privileges(redfish::privileges::patchManager)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002327 .methods(boost::beast::http::verb::patch)(
2328 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002329 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2330 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002331 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2332 {
2333 return;
2334 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002335
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002336 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2337 {
2338 messages::resourceNotFound(asyncResp->res, "Manager",
2339 managerId);
2340 return;
2341 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002342
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002343 std::optional<std::string> activeSoftwareImageOdataId;
2344 std::optional<std::string> datetime;
2345 std::optional<nlohmann::json::object_t> pidControllers;
2346 std::optional<nlohmann::json::object_t> fanControllers;
2347 std::optional<nlohmann::json::object_t> fanZones;
2348 std::optional<nlohmann::json::object_t> stepwiseControllers;
2349 std::optional<std::string> profile;
Ed Tanous002d39b2022-05-31 08:59:27 -07002350
Myung Baeafc474a2024-10-09 00:53:29 -07002351 if (!json_util::readJsonPatch( //
2352 req, asyncResp->res, //
2353 "DateTime", datetime, //
2354 "Links/ActiveSoftwareImage/@odata.id",
2355 activeSoftwareImageOdataId, //
2356 "Oem/OpenBmc/Fan/FanControllers", fanControllers, //
2357 "Oem/OpenBmc/Fan/FanZones", fanZones, //
2358 "Oem/OpenBmc/Fan/PidControllers", pidControllers, //
2359 "Oem/OpenBmc/Fan/Profile", profile, //
2360 "Oem/OpenBmc/Fan/StepwiseControllers",
2361 stepwiseControllers //
2362 ))
2363 {
2364 return;
2365 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002366
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002367 if (pidControllers || fanControllers || fanZones ||
2368 stepwiseControllers || profile)
2369 {
2370 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
2371 {
2372 std::vector<
2373 std::pair<std::string,
Ed Tanous25b54db2024-04-17 15:40:31 -07002374 std::optional<nlohmann::json::object_t>>>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002375 configuration;
2376 if (pidControllers)
2377 {
2378 configuration.emplace_back(
2379 "PidControllers", std::move(pidControllers));
2380 }
2381 if (fanControllers)
2382 {
2383 configuration.emplace_back(
2384 "FanControllers", std::move(fanControllers));
2385 }
2386 if (fanZones)
2387 {
2388 configuration.emplace_back("FanZones",
2389 std::move(fanZones));
2390 }
2391 if (stepwiseControllers)
2392 {
2393 configuration.emplace_back(
2394 "StepwiseControllers",
2395 std::move(stepwiseControllers));
2396 }
2397 auto pid = std::make_shared<SetPIDValues>(
2398 asyncResp, std::move(configuration), profile);
2399 pid->run();
2400 }
2401 else
2402 {
2403 messages::propertyUnknown(asyncResp->res, "Oem");
2404 return;
2405 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002406 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002407
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002408 if (activeSoftwareImageOdataId)
2409 {
2410 setActiveFirmwareImage(asyncResp,
2411 *activeSoftwareImageOdataId);
2412 }
Ed Tanous9e9b6042024-03-06 14:18:28 -08002413
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002414 if (datetime)
2415 {
2416 setDateTime(asyncResp, *datetime);
2417 }
2418 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002419}
2420
2421inline void requestRoutesManagerCollection(App& app)
2422{
2423 BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
Ed Tanoused398212021-06-09 17:05:54 -07002424 .privileges(redfish::privileges::getManagerCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002425 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002426 [&app](const crow::Request& req,
2427 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002428 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2429 {
2430 return;
2431 }
2432 // Collections don't include the static data added by SubRoute
2433 // because it has a duplicate entry for members
2434 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
2435 asyncResp->res.jsonValue["@odata.type"] =
2436 "#ManagerCollection.ManagerCollection";
2437 asyncResp->res.jsonValue["Name"] = "Manager Collection";
2438 asyncResp->res.jsonValue["Members@odata.count"] = 1;
2439 nlohmann::json::array_t members;
2440 nlohmann::json& bmc = members.emplace_back();
2441 bmc["@odata.id"] = boost::urls::format(
2442 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2443 asyncResp->res.jsonValue["Members"] = std::move(members);
2444 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002445}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002446} // namespace redfish