blob: e20624ed9e7f8812604fa3cb15f08cf9faf3045f [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
53/**
Gunnar Mills2a5c4402020-05-19 09:07:24 -050054 * Function reboots the BMC.
55 *
56 * @param[in] asyncResp - Shared pointer for completing asynchronous calls
Jennifer Leeed5befb2018-08-10 11:29:45 -070057 */
zhanghch058d1b46d2021-04-01 11:18:24 +080058inline void
59 doBMCGracefulRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Gunnar Mills2a5c4402020-05-19 09:07:24 -050060{
61 const char* processName = "xyz.openbmc_project.State.BMC";
62 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
63 const char* interfaceName = "xyz.openbmc_project.State.BMC";
64 const std::string& propertyValue =
65 "xyz.openbmc_project.State.BMC.Transition.Reboot";
66 const char* destProperty = "RequestedBMCTransition";
67
68 // Create the D-Bus variant for D-Bus call.
George Liu9ae226f2023-06-21 17:56:46 +080069 sdbusplus::asio::setProperty(
70 *crow::connections::systemBus, processName, objectPath, interfaceName,
71 destProperty, propertyValue,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080072 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040073 // Use "Set" method to set the property value.
74 if (ec)
75 {
76 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
77 messages::internalError(asyncResp->res);
78 return;
79 }
Gunnar Mills2a5c4402020-05-19 09:07:24 -050080
Patrick Williamsbd79bce2024-08-16 15:22:20 -040081 messages::success(asyncResp->res);
82 });
Gunnar Mills2a5c4402020-05-19 09:07:24 -050083}
84
zhanghch058d1b46d2021-04-01 11:18:24 +080085inline void
86 doBMCForceRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +000087{
88 const char* processName = "xyz.openbmc_project.State.BMC";
89 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
90 const char* interfaceName = "xyz.openbmc_project.State.BMC";
91 const std::string& propertyValue =
92 "xyz.openbmc_project.State.BMC.Transition.HardReboot";
93 const char* destProperty = "RequestedBMCTransition";
94
95 // Create the D-Bus variant for D-Bus call.
George Liu9ae226f2023-06-21 17:56:46 +080096 sdbusplus::asio::setProperty(
97 *crow::connections::systemBus, processName, objectPath, interfaceName,
98 destProperty, propertyValue,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080099 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400100 // Use "Set" method to set the property value.
101 if (ec)
102 {
103 BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec);
104 messages::internalError(asyncResp->res);
105 return;
106 }
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000107
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400108 messages::success(asyncResp->res);
109 });
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000110}
111
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500112/**
113 * ManagerResetAction class supports the POST method for the Reset (reboot)
114 * action.
115 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700116inline void requestRoutesManagerResetAction(App& app)
Jennifer Leeed5befb2018-08-10 11:29:45 -0700117{
Jennifer Leeed5befb2018-08-10 11:29:45 -0700118 /**
Jennifer Leeed5befb2018-08-10 11:29:45 -0700119 * Function handles POST method request.
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500120 * Analyzes POST body before sending Reset (Reboot) request data to D-Bus.
Jayaprakash Mutyalaf92af382020-06-16 23:29:41 +0000121 * OpenBMC supports ResetType "GracefulRestart" and "ForceRestart".
Jennifer Leeed5befb2018-08-10 11:29:45 -0700122 */
Jennifer Leeed5befb2018-08-10 11:29:45 -0700123
Ed Tanous253f11b2024-05-16 09:38:31 -0700124 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Actions/Manager.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700125 .privileges(redfish::privileges::postManager)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700126 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700127 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700128 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
129 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400130 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
131 {
132 return;
133 }
134 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
135 {
136 messages::resourceNotFound(asyncResp->res, "Manager",
137 managerId);
138 return;
139 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700140
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400141 BMCWEB_LOG_DEBUG("Post Manager Reset.");
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500142
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400143 std::string resetType;
Jennifer Leeed5befb2018-08-10 11:29:45 -0700144
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400145 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
146 resetType))
147 {
148 return;
149 }
Gunnar Mills2a5c4402020-05-19 09:07:24 -0500150
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400151 if (resetType == "GracefulRestart")
152 {
153 BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
154 doBMCGracefulRestart(asyncResp);
155 return;
156 }
157 if (resetType == "ForceRestart")
158 {
159 BMCWEB_LOG_DEBUG("Proceeding with {}", resetType);
160 doBMCForceRestart(asyncResp);
161 return;
162 }
163 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
164 resetType);
165 messages::actionParameterNotSupported(asyncResp->res, resetType,
166 "ResetType");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400168 return;
169 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700170}
Jennifer Leeed5befb2018-08-10 11:29:45 -0700171
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500172/**
173 * ManagerResetToDefaultsAction class supports POST method for factory reset
174 * action.
175 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700176inline void requestRoutesManagerResetToDefaultsAction(App& app)
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500177{
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500178 /**
179 * Function handles ResetToDefaults POST method request.
180 *
181 * Analyzes POST body message and factory resets BMC by calling
182 * BMC code updater factory reset followed by a BMC reboot.
183 *
184 * BMC code updater factory reset wipes the whole BMC read-write
185 * filesystem which includes things like the network settings.
186 *
187 * OpenBMC only supports ResetToDefaultsType "ResetAll".
188 */
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500189
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700190 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -0700191 "/redfish/v1/Managers/<str>/Actions/Manager.ResetToDefaults/")
Ed Tanoused398212021-06-09 17:05:54 -0700192 .privileges(redfish::privileges::postManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400193 .methods(
194 boost::beast::http::verb::
195 post)([&app](
196 const crow::Request& req,
197 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
198 const std::string& managerId) {
199 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700200 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700201 return;
202 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400203
204 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
205 {
206 messages::resourceNotFound(asyncResp->res, "Manager",
207 managerId);
208 return;
209 }
210
211 BMCWEB_LOG_DEBUG("Post ResetToDefaults.");
212
213 std::optional<std::string> resetType;
214 std::optional<std::string> resetToDefaultsType;
215
Myung Baeafc474a2024-10-09 00:53:29 -0700216 if (!json_util::readJsonAction( //
217 req, asyncResp->res, //
218 "ResetToDefaultsType", resetToDefaultsType, //
219 "ResetType", resetType //
220 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400221 {
222 BMCWEB_LOG_DEBUG("Missing property ResetType.");
223
224 messages::actionParameterMissing(
225 asyncResp->res, "ResetToDefaults", "ResetType");
226 return;
227 }
228
229 if (resetToDefaultsType && !resetType)
230 {
231 BMCWEB_LOG_WARNING(
232 "Using deprecated ResetToDefaultsType, should be ResetType."
233 "Support for the ResetToDefaultsType will be dropped in 2Q24");
234 resetType = resetToDefaultsType;
235 }
236
237 if (resetType != "ResetAll")
238 {
239 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
240 *resetType);
241 messages::actionParameterNotSupported(asyncResp->res,
242 *resetType, "ResetType");
243 return;
244 }
245
246 crow::connections::systemBus->async_method_call(
247 [asyncResp](const boost::system::error_code& ec) {
248 if (ec)
249 {
250 BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec);
251 messages::internalError(asyncResp->res);
252 return;
253 }
254 // Factory Reset doesn't actually happen until a reboot
255 // Can't erase what the BMC is running on
256 doBMCGracefulRestart(asyncResp);
257 },
258 "xyz.openbmc_project.Software.BMC.Updater",
259 "/xyz/openbmc_project/software",
260 "xyz.openbmc_project.Common.FactoryReset", "Reset");
261 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700262}
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500263
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530264/**
265 * ManagerResetActionInfo derived class for delivering Manager
266 * ResetType AllowableValues using ResetInfo schema.
267 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700268inline void requestRoutesManagerResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530269{
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530270 /**
271 * Functions triggers appropriate requests on DBus
272 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700273
Ed Tanous253f11b2024-05-16 09:38:31 -0700274 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700275 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700276 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700277 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700278 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
279 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400280 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
281 {
282 return;
283 }
Ed Tanous14766872022-03-15 10:44:42 -0700284
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400285 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
286 {
287 messages::resourceNotFound(asyncResp->res, "Manager",
288 managerId);
289 return;
290 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700291
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400292 asyncResp->res.jsonValue["@odata.type"] =
293 "#ActionInfo.v1_1_2.ActionInfo";
294 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
295 "/redfish/v1/Managers/{}/ResetActionInfo",
296 BMCWEB_REDFISH_MANAGER_URI_NAME);
297 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
298 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
299 nlohmann::json::object_t parameter;
300 parameter["Name"] = "ResetType";
301 parameter["Required"] = true;
302 parameter["DataType"] = action_info::ParameterTypes::String;
Ed Tanous14766872022-03-15 10:44:42 -0700303
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400304 nlohmann::json::array_t allowableValues;
305 allowableValues.emplace_back("GracefulRestart");
306 allowableValues.emplace_back("ForceRestart");
307 parameter["AllowableValues"] = std::move(allowableValues);
Ed Tanous14766872022-03-15 10:44:42 -0700308
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400309 nlohmann::json::array_t parameters;
310 parameters.emplace_back(std::move(parameter));
Ed Tanous14766872022-03-15 10:44:42 -0700311
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400312 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
313 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700314}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530315
James Feist5b4aa862018-08-16 14:07:01 -0700316static constexpr const char* objectManagerIface =
317 "org.freedesktop.DBus.ObjectManager";
318static constexpr const char* pidConfigurationIface =
319 "xyz.openbmc_project.Configuration.Pid";
320static constexpr const char* pidZoneConfigurationIface =
321 "xyz.openbmc_project.Configuration.Pid.Zone";
James Feistb7a08d02018-12-11 14:55:37 -0800322static constexpr const char* stepwiseConfigurationIface =
323 "xyz.openbmc_project.Configuration.Stepwise";
James Feist73df0db2019-03-25 15:29:35 -0700324static constexpr const char* thermalModeIface =
325 "xyz.openbmc_project.Control.ThermalMode";
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100326
zhanghch058d1b46d2021-04-01 11:18:24 +0800327inline void
328 asyncPopulatePid(const std::string& connection, const std::string& path,
329 const std::string& currentProfile,
330 const std::vector<std::string>& supportedProfiles,
331 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
James Feist5b4aa862018-08-16 14:07:01 -0700332{
George Liu5eb468d2023-06-20 17:03:24 +0800333 sdbusplus::message::object_path objPath(path);
334 dbus::utility::getManagedObjects(
335 connection, objPath,
James Feist73df0db2019-03-25 15:29:35 -0700336 [asyncResp, currentProfile, supportedProfiles](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800337 const boost::system::error_code& ec,
James Feist73df0db2019-03-25 15:29:35 -0700338 const dbus::utility::ManagedObjectType& managedObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400339 if (ec)
James Feist5b4aa862018-08-16 14:07:01 -0700340 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400341 BMCWEB_LOG_ERROR("{}", ec);
342 messages::internalError(asyncResp->res);
343 return;
344 }
345 nlohmann::json& configRoot =
346 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
347 nlohmann::json& fans = configRoot["FanControllers"];
348 fans["@odata.type"] =
349 "#OpenBMCManager.v1_0_0.Manager.FanControllers";
350 fans["@odata.id"] = boost::urls::format(
351 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
352 BMCWEB_REDFISH_MANAGER_URI_NAME);
353
354 nlohmann::json& pids = configRoot["PidControllers"];
355 pids["@odata.type"] =
356 "#OpenBMCManager.v1_0_0.Manager.PidControllers";
357 pids["@odata.id"] = boost::urls::format(
358 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
359 BMCWEB_REDFISH_MANAGER_URI_NAME);
360
361 nlohmann::json& stepwise = configRoot["StepwiseControllers"];
362 stepwise["@odata.type"] =
363 "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
364 stepwise["@odata.id"] = boost::urls::format(
365 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
366 BMCWEB_REDFISH_MANAGER_URI_NAME);
367
368 nlohmann::json& zones = configRoot["FanZones"];
369 zones["@odata.id"] = boost::urls::format(
370 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
371 BMCWEB_REDFISH_MANAGER_URI_NAME);
372 zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
373 configRoot["@odata.id"] =
374 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
375 BMCWEB_REDFISH_MANAGER_URI_NAME);
376 configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
377 configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
378
379 if (!currentProfile.empty())
380 {
381 configRoot["Profile"] = currentProfile;
382 }
383 BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
384
385 for (const auto& pathPair : managedObj)
386 {
387 for (const auto& intfPair : pathPair.second)
James Feist5b4aa862018-08-16 14:07:01 -0700388 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400389 if (intfPair.first != pidConfigurationIface &&
390 intfPair.first != pidZoneConfigurationIface &&
391 intfPair.first != stepwiseConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700392 {
393 continue;
394 }
395
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400396 std::string name;
397
398 for (const std::pair<std::string,
399 dbus::utility::DbusVariantType>&
400 propPair : intfPair.second)
401 {
402 if (propPair.first == "Name")
403 {
404 const std::string* namePtr =
405 std::get_if<std::string>(&propPair.second);
406 if (namePtr == nullptr)
407 {
408 BMCWEB_LOG_ERROR("Pid Name Field illegal");
409 messages::internalError(asyncResp->res);
410 return;
411 }
412 name = *namePtr;
413 dbus::utility::escapePathForDbus(name);
414 }
415 else if (propPair.first == "Profiles")
416 {
417 const std::vector<std::string>* profiles =
418 std::get_if<std::vector<std::string>>(
419 &propPair.second);
420 if (profiles == nullptr)
421 {
422 BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
423 messages::internalError(asyncResp->res);
424 return;
425 }
426 if (std::find(profiles->begin(), profiles->end(),
427 currentProfile) == profiles->end())
428 {
429 BMCWEB_LOG_INFO(
430 "{} not supported in current profile",
431 name);
432 continue;
433 }
434 }
435 }
436 nlohmann::json* config = nullptr;
437 const std::string* classPtr = nullptr;
438
439 for (const std::pair<std::string,
440 dbus::utility::DbusVariantType>&
441 propPair : intfPair.second)
442 {
443 if (propPair.first == "Class")
444 {
445 classPtr =
446 std::get_if<std::string>(&propPair.second);
447 }
448 }
449
450 boost::urls::url url(
451 boost::urls::format("/redfish/v1/Managers/{}",
452 BMCWEB_REDFISH_MANAGER_URI_NAME));
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 if (intfPair.first == pidZoneConfigurationIface)
454 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400455 std::string chassis;
456 if (!dbus::utility::getNthStringFromPath(
457 pathPair.first.str, 5, chassis))
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400459 chassis = "#IllegalValue";
460 }
461 nlohmann::json& zone = zones[name];
462 zone["Chassis"]["@odata.id"] = boost::urls::format(
463 "/redfish/v1/Chassis/{}", chassis);
464 url.set_fragment(
465 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
466 .to_string());
467 zone["@odata.id"] = std::move(url);
468 zone["@odata.type"] =
469 "#OpenBMCManager.v1_0_0.Manager.FanZone";
470 config = &zone;
471 }
472
473 else if (intfPair.first == stepwiseConfigurationIface)
474 {
475 if (classPtr == nullptr)
476 {
477 BMCWEB_LOG_ERROR("Pid Class Field illegal");
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 messages::internalError(asyncResp->res);
479 return;
480 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700481
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400482 nlohmann::json& controller = stepwise[name];
483 config = &controller;
484 url.set_fragment(
485 ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
486 name)
487 .to_string());
488 controller["@odata.id"] = std::move(url);
489 controller["@odata.type"] =
490 "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700491
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400492 controller["Direction"] = *classPtr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 }
James Feistb7a08d02018-12-11 14:55:37 -0800494
Ed Tanous002d39b2022-05-31 08:59:27 -0700495 // pid and fans are off the same configuration
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400496 else if (intfPair.first == pidConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700497 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400498 if (classPtr == nullptr)
James Feistb7a08d02018-12-11 14:55:37 -0800499 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400500 BMCWEB_LOG_ERROR("Pid Class Field illegal");
501 messages::internalError(asyncResp->res);
502 return;
James Feist5b4aa862018-08-16 14:07:01 -0700503 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400504 bool isFan = *classPtr == "fan";
505 nlohmann::json& element =
506 isFan ? fans[name] : pids[name];
507 config = &element;
508 if (isFan)
James Feist5b4aa862018-08-16 14:07:01 -0700509 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400510 url.set_fragment(
511 ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
512 name)
513 .to_string());
514 element["@odata.id"] = std::move(url);
515 element["@odata.type"] =
516 "#OpenBMCManager.v1_0_0.Manager.FanController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400518 else
Ed Tanous002d39b2022-05-31 08:59:27 -0700519 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400520 url.set_fragment(
521 ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
522 name)
523 .to_string());
524 element["@odata.id"] = std::move(url);
525 element["@odata.type"] =
526 "#OpenBMCManager.v1_0_0.Manager.PidController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700527 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400528 }
529 else
530 {
531 BMCWEB_LOG_ERROR("Unexpected configuration");
532 messages::internalError(asyncResp->res);
533 return;
534 }
535
536 // used for making maps out of 2 vectors
537 const std::vector<double>* keys = nullptr;
538 const std::vector<double>* values = nullptr;
539
540 for (const auto& propertyPair : intfPair.second)
541 {
542 if (propertyPair.first == "Type" ||
543 propertyPair.first == "Class" ||
544 propertyPair.first == "Name")
545 {
546 continue;
547 }
548
549 // zones
550 if (intfPair.first == pidZoneConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700551 {
552 const double* ptr =
553 std::get_if<double>(&propertyPair.second);
554 if (ptr == nullptr)
555 {
Ed Tanous62598e32023-07-17 17:06:25 -0700556 BMCWEB_LOG_ERROR("Field Illegal {}",
557 propertyPair.first);
Ed Tanous002d39b2022-05-31 08:59:27 -0700558 messages::internalError(asyncResp->res);
559 return;
560 }
561 (*config)[propertyPair.first] = *ptr;
James Feist5b4aa862018-08-16 14:07:01 -0700562 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400563
564 if (intfPair.first == stepwiseConfigurationIface)
565 {
566 if (propertyPair.first == "Reading" ||
567 propertyPair.first == "Output")
568 {
569 const std::vector<double>* ptr =
570 std::get_if<std::vector<double>>(
571 &propertyPair.second);
572
573 if (ptr == nullptr)
574 {
575 BMCWEB_LOG_ERROR("Field Illegal {}",
576 propertyPair.first);
577 messages::internalError(asyncResp->res);
578 return;
579 }
580
581 if (propertyPair.first == "Reading")
582 {
583 keys = ptr;
584 }
585 else
586 {
587 values = ptr;
588 }
589 if (keys != nullptr && values != nullptr)
590 {
591 if (keys->size() != values->size())
592 {
593 BMCWEB_LOG_ERROR(
594 "Reading and Output size don't match ");
595 messages::internalError(asyncResp->res);
596 return;
597 }
598 nlohmann::json& steps = (*config)["Steps"];
599 steps = nlohmann::json::array();
600 for (size_t ii = 0; ii < keys->size(); ii++)
601 {
602 nlohmann::json::object_t step;
603 step["Target"] = (*keys)[ii];
604 step["Output"] = (*values)[ii];
605 steps.emplace_back(std::move(step));
606 }
607 }
608 }
609 if (propertyPair.first == "NegativeHysteresis" ||
610 propertyPair.first == "PositiveHysteresis")
611 {
612 const double* ptr =
613 std::get_if<double>(&propertyPair.second);
614 if (ptr == nullptr)
615 {
616 BMCWEB_LOG_ERROR("Field Illegal {}",
617 propertyPair.first);
618 messages::internalError(asyncResp->res);
619 return;
620 }
621 (*config)[propertyPair.first] = *ptr;
622 }
623 }
624
625 // pid and fans are off the same configuration
626 if (intfPair.first == pidConfigurationIface ||
627 intfPair.first == stepwiseConfigurationIface)
628 {
629 if (propertyPair.first == "Zones")
630 {
631 const std::vector<std::string>* inputs =
632 std::get_if<std::vector<std::string>>(
633 &propertyPair.second);
634
635 if (inputs == nullptr)
636 {
637 BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
638 messages::internalError(asyncResp->res);
639 return;
640 }
641 auto& data = (*config)[propertyPair.first];
642 data = nlohmann::json::array();
643 for (std::string itemCopy : *inputs)
644 {
645 dbus::utility::escapePathForDbus(itemCopy);
646 nlohmann::json::object_t input;
647 boost::urls::url managerUrl =
648 boost::urls::format(
649 "/redfish/v1/Managers/{}#{}",
650 BMCWEB_REDFISH_MANAGER_URI_NAME,
651 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
652 itemCopy)
653 .to_string());
654 input["@odata.id"] = std::move(managerUrl);
655 data.emplace_back(std::move(input));
656 }
657 }
658 // todo(james): may never happen, but this
659 // assumes configuration data referenced in the
660 // PID config is provided by the same daemon, we
661 // could add another loop to cover all cases,
662 // but I'm okay kicking this can down the road a
663 // bit
664
665 else if (propertyPair.first == "Inputs" ||
666 propertyPair.first == "Outputs")
667 {
668 auto& data = (*config)[propertyPair.first];
669 const std::vector<std::string>* inputs =
670 std::get_if<std::vector<std::string>>(
671 &propertyPair.second);
672
673 if (inputs == nullptr)
674 {
675 BMCWEB_LOG_ERROR("Field Illegal {}",
676 propertyPair.first);
677 messages::internalError(asyncResp->res);
678 return;
679 }
680 data = *inputs;
681 }
682 else if (propertyPair.first == "SetPointOffset")
683 {
684 const std::string* ptr =
685 std::get_if<std::string>(
686 &propertyPair.second);
687
688 if (ptr == nullptr)
689 {
690 BMCWEB_LOG_ERROR("Field Illegal {}",
691 propertyPair.first);
692 messages::internalError(asyncResp->res);
693 return;
694 }
695 // translate from dbus to redfish
696 if (*ptr == "WarningHigh")
697 {
698 (*config)["SetPointOffset"] =
699 "UpperThresholdNonCritical";
700 }
701 else if (*ptr == "WarningLow")
702 {
703 (*config)["SetPointOffset"] =
704 "LowerThresholdNonCritical";
705 }
706 else if (*ptr == "CriticalHigh")
707 {
708 (*config)["SetPointOffset"] =
709 "UpperThresholdCritical";
710 }
711 else if (*ptr == "CriticalLow")
712 {
713 (*config)["SetPointOffset"] =
714 "LowerThresholdCritical";
715 }
716 else
717 {
718 BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
719 messages::internalError(asyncResp->res);
720 return;
721 }
722 }
723 // doubles
724 else if (propertyPair.first ==
725 "FFGainCoefficient" ||
726 propertyPair.first == "FFOffCoefficient" ||
727 propertyPair.first == "ICoefficient" ||
728 propertyPair.first == "ILimitMax" ||
729 propertyPair.first == "ILimitMin" ||
730 propertyPair.first ==
731 "PositiveHysteresis" ||
732 propertyPair.first ==
733 "NegativeHysteresis" ||
734 propertyPair.first == "OutLimitMax" ||
735 propertyPair.first == "OutLimitMin" ||
736 propertyPair.first == "PCoefficient" ||
737 propertyPair.first == "SetPoint" ||
738 propertyPair.first == "SlewNeg" ||
739 propertyPair.first == "SlewPos")
740 {
741 const double* ptr =
742 std::get_if<double>(&propertyPair.second);
743 if (ptr == nullptr)
744 {
745 BMCWEB_LOG_ERROR("Field Illegal {}",
746 propertyPair.first);
747 messages::internalError(asyncResp->res);
748 return;
749 }
750 (*config)[propertyPair.first] = *ptr;
751 }
752 }
James Feist5b4aa862018-08-16 14:07:01 -0700753 }
754 }
755 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400756 });
James Feist5b4aa862018-08-16 14:07:01 -0700757}
Jennifer Leeca537922018-08-10 10:07:30 -0700758
James Feist83ff9ab2018-08-31 10:18:24 -0700759enum class CreatePIDRet
760{
761 fail,
762 del,
763 patch
764};
765
zhanghch058d1b46d2021-04-01 11:18:24 +0800766inline bool
767 getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800768 std::vector<nlohmann::json::object_t>& config,
zhanghch058d1b46d2021-04-01 11:18:24 +0800769 std::vector<std::string>& zones)
James Feist5f2caae2018-12-12 14:08:25 -0800770{
James Feistb6baeaa2019-02-21 10:41:40 -0800771 if (config.empty())
772 {
Ed Tanous62598e32023-07-17 17:06:25 -0700773 BMCWEB_LOG_ERROR("Empty Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700774 messages::propertyValueFormatError(response->res, config, "Zones");
James Feistb6baeaa2019-02-21 10:41:40 -0800775 return false;
776 }
James Feist5f2caae2018-12-12 14:08:25 -0800777 for (auto& odata : config)
778 {
779 std::string path;
Ed Tanous9e9b6042024-03-06 14:18:28 -0800780 if (!redfish::json_util::readJsonObject(odata, response->res,
781 "@odata.id", path))
James Feist5f2caae2018-12-12 14:08:25 -0800782 {
783 return false;
784 }
785 std::string input;
James Feist61adbda2019-03-25 13:03:51 -0700786
787 // 8 below comes from
788 // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
789 // 0 1 2 3 4 5 6 7 8
790 if (!dbus::utility::getNthStringFromPath(path, 8, input))
James Feist5f2caae2018-12-12 14:08:25 -0800791 {
Ed Tanous62598e32023-07-17 17:06:25 -0700792 BMCWEB_LOG_ERROR("Got invalid path {}", path);
793 BMCWEB_LOG_ERROR("Illegal Type Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700794 messages::propertyValueFormatError(response->res, odata, "Zones");
James Feist5f2caae2018-12-12 14:08:25 -0800795 return false;
796 }
Ed Tanousa170f272022-06-30 21:53:27 -0700797 std::replace(input.begin(), input.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -0800798 zones.emplace_back(std::move(input));
799 }
800 return true;
801}
802
Ed Tanous711ac7a2021-12-20 09:34:41 -0800803inline const dbus::utility::ManagedObjectType::value_type*
James Feist73df0db2019-03-25 15:29:35 -0700804 findChassis(const dbus::utility::ManagedObjectType& managedObj,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800805 std::string_view value, std::string& chassis)
James Feistb6baeaa2019-02-21 10:41:40 -0800806{
Ed Tanous62598e32023-07-17 17:06:25 -0700807 BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
James Feistb6baeaa2019-02-21 10:41:40 -0800808
Ed Tanous9e9b6042024-03-06 14:18:28 -0800809 std::string escaped(value);
Yaswanth Reddy M6ce82fa2023-03-10 07:29:45 +0000810 std::replace(escaped.begin(), escaped.end(), ' ', '_');
James Feistb6baeaa2019-02-21 10:41:40 -0800811 escaped = "/" + escaped;
Ed Tanous3544d2a2023-08-06 18:12:20 -0700812 auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
Ed Tanous18f8f602023-07-18 10:07:23 -0700813 if (obj.first.str.ends_with(escaped))
Ed Tanous002d39b2022-05-31 08:59:27 -0700814 {
Ed Tanous62598e32023-07-17 17:06:25 -0700815 BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700816 return true;
817 }
818 return false;
819 });
James Feistb6baeaa2019-02-21 10:41:40 -0800820
821 if (it == managedObj.end())
822 {
James Feist73df0db2019-03-25 15:29:35 -0700823 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800824 }
825 // 5 comes from <chassis-name> being the 5th element
826 // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
James Feist73df0db2019-03-25 15:29:35 -0700827 if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
828 {
829 return &(*it);
830 }
831
832 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800833}
834
Ed Tanous23a21a12020-07-25 04:45:05 +0000835inline CreatePIDRet createPidInterface(
zhanghch058d1b46d2021-04-01 11:18:24 +0800836 const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800837 std::string_view name, nlohmann::json& jsonValue, const std::string& path,
James Feist83ff9ab2018-08-31 10:18:24 -0700838 const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800839 dbus::utility::DBusPropertiesMap& output, std::string& chassis,
840 const std::string& profile)
James Feist83ff9ab2018-08-31 10:18:24 -0700841{
James Feist5f2caae2018-12-12 14:08:25 -0800842 // common deleter
Ed Tanous9e9b6042024-03-06 14:18:28 -0800843 if (jsonValue == nullptr)
James Feist5f2caae2018-12-12 14:08:25 -0800844 {
845 std::string iface;
846 if (type == "PidControllers" || type == "FanControllers")
847 {
848 iface = pidConfigurationIface;
849 }
850 else if (type == "FanZones")
851 {
852 iface = pidZoneConfigurationIface;
853 }
854 else if (type == "StepwiseControllers")
855 {
856 iface = stepwiseConfigurationIface;
857 }
858 else
859 {
Ed Tanous62598e32023-07-17 17:06:25 -0700860 BMCWEB_LOG_ERROR("Illegal Type {}", type);
James Feist5f2caae2018-12-12 14:08:25 -0800861 messages::propertyUnknown(response->res, type);
862 return CreatePIDRet::fail;
863 }
James Feist6ee7f772020-02-06 16:25:27 -0800864
Ed Tanous62598e32023-07-17 17:06:25 -0700865 BMCWEB_LOG_DEBUG("del {} {}", path, iface);
James Feist5f2caae2018-12-12 14:08:25 -0800866 // delete interface
867 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800868 [response, path](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400869 if (ec)
870 {
871 BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
872 messages::internalError(response->res);
873 return;
874 }
875 messages::success(response->res);
876 },
James Feist5f2caae2018-12-12 14:08:25 -0800877 "xyz.openbmc_project.EntityManager", path, iface, "Delete");
878 return CreatePIDRet::del;
879 }
880
Ed Tanous711ac7a2021-12-20 09:34:41 -0800881 const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800882 if (!createNewObject)
883 {
884 // if we aren't creating a new object, we should be able to find it on
885 // d-bus
Ed Tanous9e9b6042024-03-06 14:18:28 -0800886 managedItem = findChassis(managedObj, name, chassis);
James Feist73df0db2019-03-25 15:29:35 -0700887 if (managedItem == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -0800888 {
Ed Tanous62598e32023-07-17 17:06:25 -0700889 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousef4c65b2023-04-24 15:28:50 -0700890 messages::invalidObject(
891 response->res,
892 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -0800893 return CreatePIDRet::fail;
894 }
895 }
896
Ed Tanous26f69762022-01-25 09:49:11 -0800897 if (!profile.empty() &&
James Feist73df0db2019-03-25 15:29:35 -0700898 (type == "PidControllers" || type == "FanControllers" ||
899 type == "StepwiseControllers"))
900 {
901 if (managedItem == nullptr)
902 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800903 output.emplace_back("Profiles", std::vector<std::string>{profile});
James Feist73df0db2019-03-25 15:29:35 -0700904 }
905 else
906 {
907 std::string interface;
908 if (type == "StepwiseControllers")
909 {
910 interface = stepwiseConfigurationIface;
911 }
912 else
913 {
914 interface = pidConfigurationIface;
915 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800916 bool ifaceFound = false;
917 for (const auto& iface : managedItem->second)
918 {
919 if (iface.first == interface)
920 {
921 ifaceFound = true;
922 for (const auto& prop : iface.second)
923 {
924 if (prop.first == "Profiles")
925 {
926 const std::vector<std::string>* curProfiles =
927 std::get_if<std::vector<std::string>>(
928 &(prop.second));
929 if (curProfiles == nullptr)
930 {
Ed Tanous62598e32023-07-17 17:06:25 -0700931 BMCWEB_LOG_ERROR(
932 "Illegal profiles in managed object");
Ed Tanous711ac7a2021-12-20 09:34:41 -0800933 messages::internalError(response->res);
934 return CreatePIDRet::fail;
935 }
936 if (std::find(curProfiles->begin(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400937 curProfiles->end(), profile) ==
938 curProfiles->end())
Ed Tanous711ac7a2021-12-20 09:34:41 -0800939 {
940 std::vector<std::string> newProfiles =
941 *curProfiles;
942 newProfiles.push_back(profile);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800943 output.emplace_back("Profiles", newProfiles);
Ed Tanous711ac7a2021-12-20 09:34:41 -0800944 }
945 }
946 }
947 }
948 }
949
950 if (!ifaceFound)
James Feist73df0db2019-03-25 15:29:35 -0700951 {
Ed Tanous62598e32023-07-17 17:06:25 -0700952 BMCWEB_LOG_ERROR("Failed to find interface in managed object");
James Feist73df0db2019-03-25 15:29:35 -0700953 messages::internalError(response->res);
954 return CreatePIDRet::fail;
955 }
James Feist73df0db2019-03-25 15:29:35 -0700956 }
957 }
958
James Feist83ff9ab2018-08-31 10:18:24 -0700959 if (type == "PidControllers" || type == "FanControllers")
960 {
961 if (createNewObject)
962 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800963 output.emplace_back("Class",
964 type == "PidControllers" ? "temp" : "fan");
965 output.emplace_back("Type", "Pid");
James Feist83ff9ab2018-08-31 10:18:24 -0700966 }
James Feist5f2caae2018-12-12 14:08:25 -0800967
Ed Tanous9e9b6042024-03-06 14:18:28 -0800968 std::optional<std::vector<nlohmann::json::object_t>> zones;
James Feist5f2caae2018-12-12 14:08:25 -0800969 std::optional<std::vector<std::string>> inputs;
970 std::optional<std::vector<std::string>> outputs;
971 std::map<std::string, std::optional<double>> doubles;
James Feistb943aae2019-07-11 16:33:56 -0700972 std::optional<std::string> setpointOffset;
Myung Baeafc474a2024-10-09 00:53:29 -0700973 if (!redfish::json_util::readJson( //
974 jsonValue, response->res, //
975 "FFGainCoefficient", doubles["FFGainCoefficient"], //
976 "FFOffCoefficient", doubles["FFOffCoefficient"], //
977 "ICoefficient", doubles["ICoefficient"], //
978 "ILimitMax", doubles["ILimitMax"], //
979 "ILimitMin", doubles["ILimitMin"], //
980 "Inputs", inputs, //
981 "NegativeHysteresis", doubles["NegativeHysteresis"], //
982 "OutLimitMax", doubles["OutLimitMax"], //
983 "OutLimitMin", doubles["OutLimitMin"], //
984 "Outputs", outputs, //
985 "PCoefficient", doubles["PCoefficient"], //
986 "PositiveHysteresis", doubles["PositiveHysteresis"], //
987 "SetPoint", doubles["SetPoint"], //
988 "SetPointOffset", setpointOffset, //
989 "SlewNeg", doubles["SlewNeg"], //
990 "SlewPos", doubles["SlewPos"], //
991 "Zones", zones //
992 ))
James Feist83ff9ab2018-08-31 10:18:24 -0700993 {
James Feist5f2caae2018-12-12 14:08:25 -0800994 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -0700995 }
Myung Baeafc474a2024-10-09 00:53:29 -0700996
James Feist5f2caae2018-12-12 14:08:25 -0800997 if (zones)
James Feist83ff9ab2018-08-31 10:18:24 -0700998 {
James Feist5f2caae2018-12-12 14:08:25 -0800999 std::vector<std::string> zonesStr;
1000 if (!getZonesFromJsonReq(response, *zones, zonesStr))
James Feist83ff9ab2018-08-31 10:18:24 -07001001 {
Ed Tanous62598e32023-07-17 17:06:25 -07001002 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001003 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -07001004 }
James Feistb6baeaa2019-02-21 10:41:40 -08001005 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001006 findChassis(managedObj, zonesStr[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001007 {
Ed Tanous62598e32023-07-17 17:06:25 -07001008 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001009 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001010 response->res,
1011 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001012 return CreatePIDRet::fail;
1013 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001014 output.emplace_back("Zones", std::move(zonesStr));
James Feist5f2caae2018-12-12 14:08:25 -08001015 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001016
1017 if (inputs)
James Feist5f2caae2018-12-12 14:08:25 -08001018 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001019 for (std::string& value : *inputs)
James Feist83ff9ab2018-08-31 10:18:24 -07001020 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001021 std::replace(value.begin(), value.end(), '_', ' ');
James Feist83ff9ab2018-08-31 10:18:24 -07001022 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001023 output.emplace_back("Inputs", *inputs);
1024 }
1025
1026 if (outputs)
1027 {
1028 for (std::string& value : *outputs)
1029 {
1030 std::replace(value.begin(), value.end(), '_', ' ');
1031 }
1032 output.emplace_back("Outputs", *outputs);
James Feist5f2caae2018-12-12 14:08:25 -08001033 }
James Feist83ff9ab2018-08-31 10:18:24 -07001034
James Feistb943aae2019-07-11 16:33:56 -07001035 if (setpointOffset)
1036 {
1037 // translate between redfish and dbus names
1038 if (*setpointOffset == "UpperThresholdNonCritical")
1039 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001040 output.emplace_back("SetPointOffset", "WarningLow");
James Feistb943aae2019-07-11 16:33:56 -07001041 }
1042 else if (*setpointOffset == "LowerThresholdNonCritical")
1043 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001044 output.emplace_back("SetPointOffset", "WarningHigh");
James Feistb943aae2019-07-11 16:33:56 -07001045 }
1046 else if (*setpointOffset == "LowerThresholdCritical")
1047 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001048 output.emplace_back("SetPointOffset", "CriticalLow");
James Feistb943aae2019-07-11 16:33:56 -07001049 }
1050 else if (*setpointOffset == "UpperThresholdCritical")
1051 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001052 output.emplace_back("SetPointOffset", "CriticalHigh");
James Feistb943aae2019-07-11 16:33:56 -07001053 }
1054 else
1055 {
Ed Tanous62598e32023-07-17 17:06:25 -07001056 BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
Ed Tanous9e9b6042024-03-06 14:18:28 -08001057 messages::propertyValueNotInList(response->res, name,
Ed Tanousace85d62021-10-26 12:45:59 -07001058 "SetPointOffset");
James Feistb943aae2019-07-11 16:33:56 -07001059 return CreatePIDRet::fail;
1060 }
1061 }
1062
James Feist5f2caae2018-12-12 14:08:25 -08001063 // doubles
1064 for (const auto& pairs : doubles)
1065 {
1066 if (!pairs.second)
James Feist83ff9ab2018-08-31 10:18:24 -07001067 {
James Feist5f2caae2018-12-12 14:08:25 -08001068 continue;
James Feist83ff9ab2018-08-31 10:18:24 -07001069 }
Ed Tanous62598e32023-07-17 17:06:25 -07001070 BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -08001071 output.emplace_back(pairs.first, *pairs.second);
James Feist83ff9ab2018-08-31 10:18:24 -07001072 }
1073 }
James Feist5f2caae2018-12-12 14:08:25 -08001074
James Feist83ff9ab2018-08-31 10:18:24 -07001075 else if (type == "FanZones")
1076 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001077 output.emplace_back("Type", "Pid.Zone");
James Feist83ff9ab2018-08-31 10:18:24 -07001078
Ed Tanous9e9b6042024-03-06 14:18:28 -08001079 std::optional<std::string> chassisId;
James Feist5f2caae2018-12-12 14:08:25 -08001080 std::optional<double> failSafePercent;
James Feistd3ec07f2019-02-25 14:51:15 -08001081 std::optional<double> minThermalOutput;
Myung Baeafc474a2024-10-09 00:53:29 -07001082 if (!redfish::json_util::readJson( //
1083 jsonValue, response->res, //
1084 "Chassis/@odata.id", chassisId, //
1085 "FailSafePercent", failSafePercent, //
1086 "MinThermalOutput", minThermalOutput))
James Feist83ff9ab2018-08-31 10:18:24 -07001087 {
James Feist5f2caae2018-12-12 14:08:25 -08001088 return CreatePIDRet::fail;
1089 }
James Feist83ff9ab2018-08-31 10:18:24 -07001090
Ed Tanous9e9b6042024-03-06 14:18:28 -08001091 if (chassisId)
James Feist5f2caae2018-12-12 14:08:25 -08001092 {
AppaRao Puli717794d2019-10-18 22:54:53 +05301093 // /redfish/v1/chassis/chassis_name/
Ed Tanous9e9b6042024-03-06 14:18:28 -08001094 if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
James Feist5f2caae2018-12-12 14:08:25 -08001095 {
Ed Tanous9e9b6042024-03-06 14:18:28 -08001096 BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
Ed Tanousace85d62021-10-26 12:45:59 -07001097 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001098 response->res,
Ed Tanous9e9b6042024-03-06 14:18:28 -08001099 boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
James Feist5f2caae2018-12-12 14:08:25 -08001100 return CreatePIDRet::fail;
1101 }
1102 }
James Feistd3ec07f2019-02-25 14:51:15 -08001103 if (minThermalOutput)
James Feist5f2caae2018-12-12 14:08:25 -08001104 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001105 output.emplace_back("MinThermalOutput", *minThermalOutput);
James Feist5f2caae2018-12-12 14:08:25 -08001106 }
1107 if (failSafePercent)
1108 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001109 output.emplace_back("FailSafePercent", *failSafePercent);
James Feist5f2caae2018-12-12 14:08:25 -08001110 }
1111 }
1112 else if (type == "StepwiseControllers")
1113 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001114 output.emplace_back("Type", "Stepwise");
James Feist5f2caae2018-12-12 14:08:25 -08001115
Ed Tanous9e9b6042024-03-06 14:18:28 -08001116 std::optional<std::vector<nlohmann::json::object_t>> zones;
1117 std::optional<std::vector<nlohmann::json::object_t>> steps;
James Feist5f2caae2018-12-12 14:08:25 -08001118 std::optional<std::vector<std::string>> inputs;
1119 std::optional<double> positiveHysteresis;
1120 std::optional<double> negativeHysteresis;
James Feistc33a90e2019-03-01 10:17:44 -08001121 std::optional<std::string> direction; // upper clipping curve vs lower
Myung Baeafc474a2024-10-09 00:53:29 -07001122 if (!redfish::json_util::readJson( //
1123 jsonValue, response->res, //
1124 "Direction", direction, //
1125 "Inputs", inputs, //
1126 "NegativeHysteresis", negativeHysteresis, //
1127 "PositiveHysteresis", positiveHysteresis, //
1128 "Steps", steps, //
1129 "Zones", zones //
1130 ))
James Feist5f2caae2018-12-12 14:08:25 -08001131 {
James Feist5f2caae2018-12-12 14:08:25 -08001132 return CreatePIDRet::fail;
1133 }
1134
1135 if (zones)
1136 {
James Feistb6baeaa2019-02-21 10:41:40 -08001137 std::vector<std::string> zonesStrs;
1138 if (!getZonesFromJsonReq(response, *zones, zonesStrs))
James Feist5f2caae2018-12-12 14:08:25 -08001139 {
Ed Tanous62598e32023-07-17 17:06:25 -07001140 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001141 return CreatePIDRet::fail;
1142 }
James Feistb6baeaa2019-02-21 10:41:40 -08001143 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001144 findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001145 {
Ed Tanous62598e32023-07-17 17:06:25 -07001146 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001147 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001148 response->res,
1149 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001150 return CreatePIDRet::fail;
1151 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001152 output.emplace_back("Zones", std::move(zonesStrs));
James Feist5f2caae2018-12-12 14:08:25 -08001153 }
1154 if (steps)
1155 {
1156 std::vector<double> readings;
1157 std::vector<double> outputs;
1158 for (auto& step : *steps)
1159 {
Ed Tanous543f4402022-01-06 13:12:53 -08001160 double target = 0.0;
1161 double out = 0.0;
James Feist5f2caae2018-12-12 14:08:25 -08001162
Myung Baeafc474a2024-10-09 00:53:29 -07001163 if (!redfish::json_util::readJsonObject( //
1164 step, response->res, //
1165 "Output", out, //
1166 "Target", target //
1167 ))
James Feist5f2caae2018-12-12 14:08:25 -08001168 {
James Feist5f2caae2018-12-12 14:08:25 -08001169 return CreatePIDRet::fail;
1170 }
1171 readings.emplace_back(target);
Ed Tanous23a21a12020-07-25 04:45:05 +00001172 outputs.emplace_back(out);
James Feist5f2caae2018-12-12 14:08:25 -08001173 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001174 output.emplace_back("Reading", std::move(readings));
1175 output.emplace_back("Output", std::move(outputs));
James Feist5f2caae2018-12-12 14:08:25 -08001176 }
1177 if (inputs)
1178 {
1179 for (std::string& value : *inputs)
1180 {
Ed Tanousa170f272022-06-30 21:53:27 -07001181 std::replace(value.begin(), value.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -08001182 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001183 output.emplace_back("Inputs", std::move(*inputs));
James Feist5f2caae2018-12-12 14:08:25 -08001184 }
1185 if (negativeHysteresis)
1186 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001187 output.emplace_back("NegativeHysteresis", *negativeHysteresis);
James Feist5f2caae2018-12-12 14:08:25 -08001188 }
1189 if (positiveHysteresis)
1190 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001191 output.emplace_back("PositiveHysteresis", *positiveHysteresis);
James Feist83ff9ab2018-08-31 10:18:24 -07001192 }
James Feistc33a90e2019-03-01 10:17:44 -08001193 if (direction)
1194 {
1195 constexpr const std::array<const char*, 2> allowedDirections = {
1196 "Ceiling", "Floor"};
Ed Tanous3544d2a2023-08-06 18:12:20 -07001197 if (std::ranges::find(allowedDirections, *direction) ==
1198 allowedDirections.end())
James Feistc33a90e2019-03-01 10:17:44 -08001199 {
1200 messages::propertyValueTypeError(response->res, "Direction",
1201 *direction);
1202 return CreatePIDRet::fail;
1203 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001204 output.emplace_back("Class", *direction);
James Feistc33a90e2019-03-01 10:17:44 -08001205 }
James Feist83ff9ab2018-08-31 10:18:24 -07001206 }
1207 else
1208 {
Ed Tanous62598e32023-07-17 17:06:25 -07001209 BMCWEB_LOG_ERROR("Illegal Type {}", type);
Jason M. Bills35a62c72018-10-09 12:45:45 -07001210 messages::propertyUnknown(response->res, type);
James Feist83ff9ab2018-08-31 10:18:24 -07001211 return CreatePIDRet::fail;
1212 }
1213 return CreatePIDRet::patch;
1214}
James Feist73df0db2019-03-25 15:29:35 -07001215struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
1216{
Ed Tanous6936afe2022-09-08 15:10:39 -07001217 struct CompletionValues
1218 {
1219 std::vector<std::string> supportedProfiles;
1220 std::string currentProfile;
1221 dbus::utility::MapperGetSubTreeResponse subtree;
1222 };
James Feist73df0db2019-03-25 15:29:35 -07001223
Ed Tanous4e23a442022-06-06 09:57:26 -07001224 explicit GetPIDValues(
1225 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +00001226 asyncResp(asyncRespIn)
James Feist73df0db2019-03-25 15:29:35 -07001227
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001228 {}
James Feist73df0db2019-03-25 15:29:35 -07001229
1230 void run()
1231 {
1232 std::shared_ptr<GetPIDValues> self = shared_from_this();
1233
1234 // get all configurations
George Liue99073f2022-12-09 11:06:16 +08001235 constexpr std::array<std::string_view, 4> interfaces = {
1236 pidConfigurationIface, pidZoneConfigurationIface,
1237 objectManagerIface, stepwiseConfigurationIface};
1238 dbus::utility::getSubTree(
1239 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001240 [self](
George Liue99073f2022-12-09 11:06:16 +08001241 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001242 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001243 if (ec)
1244 {
1245 BMCWEB_LOG_ERROR("{}", ec);
1246 messages::internalError(self->asyncResp->res);
1247 return;
1248 }
1249 self->complete.subtree = subtreeLocal;
1250 });
James Feist73df0db2019-03-25 15:29:35 -07001251
1252 // at the same time get the selected profile
George Liue99073f2022-12-09 11:06:16 +08001253 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1254 thermalModeIface};
1255 dbus::utility::getSubTree(
1256 "/", 0, thermalModeIfaces,
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 || subtreeLocal.empty())
James Feist73df0db2019-03-25 15:29:35 -07001261 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001262 return;
1263 }
1264 if (subtreeLocal[0].second.size() != 1)
1265 {
1266 // invalid mapper response, should never happen
1267 BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
James Feist73df0db2019-03-25 15:29:35 -07001268 messages::internalError(self->asyncResp->res);
1269 return;
1270 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001271
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001272 const std::string& path = subtreeLocal[0].first;
1273 const std::string& owner = subtreeLocal[0].second[0].first;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001274
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001275 sdbusplus::asio::getAllProperties(
1276 *crow::connections::systemBus, owner, path,
1277 thermalModeIface,
1278 [path, owner,
1279 self](const boost::system::error_code& ec2,
1280 const dbus::utility::DBusPropertiesMap& resp) {
1281 if (ec2)
1282 {
1283 BMCWEB_LOG_ERROR(
1284 "GetPIDValues: Can't get thermalModeIface {}",
1285 path);
1286 messages::internalError(self->asyncResp->res);
1287 return;
1288 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001289
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001290 const std::string* current = nullptr;
1291 const std::vector<std::string>* supported = nullptr;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001292
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001293 const bool success = sdbusplus::unpackPropertiesNoThrow(
1294 dbus_utils::UnpackErrorPrinter(), resp, "Current",
1295 current, "Supported", supported);
1296
1297 if (!success)
1298 {
1299 messages::internalError(self->asyncResp->res);
1300 return;
1301 }
1302
1303 if (current == nullptr || supported == nullptr)
1304 {
1305 BMCWEB_LOG_ERROR(
1306 "GetPIDValues: thermal mode iface invalid {}",
1307 path);
1308 messages::internalError(self->asyncResp->res);
1309 return;
1310 }
1311 self->complete.currentProfile = *current;
1312 self->complete.supportedProfiles = *supported;
1313 });
George Liue99073f2022-12-09 11:06:16 +08001314 });
James Feist73df0db2019-03-25 15:29:35 -07001315 }
1316
Ed Tanous6936afe2022-09-08 15:10:39 -07001317 static void
1318 processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1319 const CompletionValues& completion)
James Feist73df0db2019-03-25 15:29:35 -07001320 {
1321 if (asyncResp->res.result() != boost::beast::http::status::ok)
1322 {
1323 return;
1324 }
1325 // create map of <connection, path to objMgr>>
Ed Tanous6936afe2022-09-08 15:10:39 -07001326 boost::container::flat_map<
1327 std::string, std::string, std::less<>,
1328 std::vector<std::pair<std::string, std::string>>>
1329 objectMgrPaths;
1330 boost::container::flat_set<std::string, std::less<>,
1331 std::vector<std::string>>
1332 calledConnections;
1333 for (const auto& pathGroup : completion.subtree)
James Feist73df0db2019-03-25 15:29:35 -07001334 {
1335 for (const auto& connectionGroup : pathGroup.second)
1336 {
1337 auto findConnection =
1338 calledConnections.find(connectionGroup.first);
1339 if (findConnection != calledConnections.end())
1340 {
1341 break;
1342 }
1343 for (const std::string& interface : connectionGroup.second)
1344 {
1345 if (interface == objectManagerIface)
1346 {
1347 objectMgrPaths[connectionGroup.first] = pathGroup.first;
1348 }
1349 // this list is alphabetical, so we
1350 // should have found the objMgr by now
1351 if (interface == pidConfigurationIface ||
1352 interface == pidZoneConfigurationIface ||
1353 interface == stepwiseConfigurationIface)
1354 {
1355 auto findObjMgr =
1356 objectMgrPaths.find(connectionGroup.first);
1357 if (findObjMgr == objectMgrPaths.end())
1358 {
Ed Tanous62598e32023-07-17 17:06:25 -07001359 BMCWEB_LOG_DEBUG("{}Has no Object Manager",
1360 connectionGroup.first);
James Feist73df0db2019-03-25 15:29:35 -07001361 continue;
1362 }
1363
1364 calledConnections.insert(connectionGroup.first);
1365
1366 asyncPopulatePid(findObjMgr->first, findObjMgr->second,
Ed Tanous6936afe2022-09-08 15:10:39 -07001367 completion.currentProfile,
1368 completion.supportedProfiles,
James Feist73df0db2019-03-25 15:29:35 -07001369 asyncResp);
1370 break;
1371 }
1372 }
1373 }
1374 }
1375 }
1376
Ed Tanous6936afe2022-09-08 15:10:39 -07001377 ~GetPIDValues()
1378 {
1379 boost::asio::post(crow::connections::systemBus->get_io_context(),
1380 std::bind_front(&processingComplete, asyncResp,
1381 std::move(complete)));
1382 }
1383
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001384 GetPIDValues(const GetPIDValues&) = delete;
1385 GetPIDValues(GetPIDValues&&) = delete;
1386 GetPIDValues& operator=(const GetPIDValues&) = delete;
1387 GetPIDValues& operator=(GetPIDValues&&) = delete;
1388
zhanghch058d1b46d2021-04-01 11:18:24 +08001389 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous6936afe2022-09-08 15:10:39 -07001390 CompletionValues complete;
James Feist73df0db2019-03-25 15:29:35 -07001391};
1392
1393struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
1394{
Ed Tanous9e9b6042024-03-06 14:18:28 -08001395 SetPIDValues(
1396 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1397 std::vector<
1398 std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
1399 configurationsIn,
1400 std::optional<std::string>& profileIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001401 asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
Ed Tanous9e9b6042024-03-06 14:18:28 -08001402 profile(std::move(profileIn))
1403 {}
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001404
1405 SetPIDValues(const SetPIDValues&) = delete;
1406 SetPIDValues(SetPIDValues&&) = delete;
1407 SetPIDValues& operator=(const SetPIDValues&) = delete;
1408 SetPIDValues& operator=(SetPIDValues&&) = delete;
1409
James Feist73df0db2019-03-25 15:29:35 -07001410 void run()
1411 {
1412 if (asyncResp->res.result() != boost::beast::http::status::ok)
1413 {
1414 return;
1415 }
1416
1417 std::shared_ptr<SetPIDValues> self = shared_from_this();
1418
1419 // todo(james): might make sense to do a mapper call here if this
1420 // interface gets more traction
George Liu5eb468d2023-06-20 17:03:24 +08001421 sdbusplus::message::object_path objPath(
1422 "/xyz/openbmc_project/inventory");
1423 dbus::utility::getManagedObjects(
1424 "xyz.openbmc_project.EntityManager", objPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001425 [self](const boost::system::error_code& ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001426 const dbus::utility::ManagedObjectType& mObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001427 if (ec)
James Feiste69d9de2020-02-07 12:23:27 -08001428 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001429 BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
1430 messages::internalError(self->asyncResp->res);
1431 return;
1432 }
1433 const std::array<const char*, 3> configurations = {
1434 pidConfigurationIface, pidZoneConfigurationIface,
1435 stepwiseConfigurationIface};
1436
1437 for (const auto& [path, object] : mObj)
1438 {
1439 for (const auto& [interface, _] : object)
James Feiste69d9de2020-02-07 12:23:27 -08001440 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001441 if (std::ranges::find(configurations, interface) !=
1442 configurations.end())
1443 {
1444 self->objectCount++;
1445 break;
1446 }
James Feiste69d9de2020-02-07 12:23:27 -08001447 }
James Feiste69d9de2020-02-07 12:23:27 -08001448 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001449 self->managedObj = mObj;
1450 });
James Feist73df0db2019-03-25 15:29:35 -07001451
1452 // at the same time get the profile information
George Liue99073f2022-12-09 11:06:16 +08001453 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1454 thermalModeIface};
1455 dbus::utility::getSubTree(
1456 "/", 0, thermalModeIfaces,
1457 [self](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001458 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001459 if (ec || subtree.empty())
James Feist73df0db2019-03-25 15:29:35 -07001460 {
James Feist73df0db2019-03-25 15:29:35 -07001461 return;
1462 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001463 if (subtree[0].second.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001464 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001465 // invalid mapper response, should never happen
1466 BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001467 messages::internalError(self->asyncResp->res);
1468 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001469 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001470
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001471 const std::string& path = subtree[0].first;
1472 const std::string& owner = subtree[0].second[0].first;
1473 sdbusplus::asio::getAllProperties(
1474 *crow::connections::systemBus, owner, path,
1475 thermalModeIface,
1476 [self, path,
1477 owner](const boost::system::error_code& ec2,
1478 const dbus::utility::DBusPropertiesMap& r) {
1479 if (ec2)
1480 {
1481 BMCWEB_LOG_ERROR(
1482 "SetPIDValues: Can't get thermalModeIface {}",
1483 path);
1484 messages::internalError(self->asyncResp->res);
1485 return;
1486 }
1487 const std::string* current = nullptr;
1488 const std::vector<std::string>* supported = nullptr;
1489
1490 const bool success = sdbusplus::unpackPropertiesNoThrow(
1491 dbus_utils::UnpackErrorPrinter(), r, "Current",
1492 current, "Supported", supported);
1493
1494 if (!success)
1495 {
1496 messages::internalError(self->asyncResp->res);
1497 return;
1498 }
1499
1500 if (current == nullptr || supported == nullptr)
1501 {
1502 BMCWEB_LOG_ERROR(
1503 "SetPIDValues: thermal mode iface invalid {}",
1504 path);
1505 messages::internalError(self->asyncResp->res);
1506 return;
1507 }
1508 self->currentProfile = *current;
1509 self->supportedProfiles = *supported;
1510 self->profileConnection = owner;
1511 self->profilePath = path;
1512 });
George Liue99073f2022-12-09 11:06:16 +08001513 });
James Feist73df0db2019-03-25 15:29:35 -07001514 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001515 void pidSetDone()
James Feist73df0db2019-03-25 15:29:35 -07001516 {
1517 if (asyncResp->res.result() != boost::beast::http::status::ok)
1518 {
1519 return;
1520 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001521 std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
James Feist73df0db2019-03-25 15:29:35 -07001522 if (profile)
1523 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07001524 if (std::ranges::find(supportedProfiles, *profile) ==
1525 supportedProfiles.end())
James Feist73df0db2019-03-25 15:29:35 -07001526 {
1527 messages::actionParameterUnknown(response->res, "Profile",
1528 *profile);
1529 return;
1530 }
1531 currentProfile = *profile;
George Liu9ae226f2023-06-21 17:56:46 +08001532 sdbusplus::asio::setProperty(
1533 *crow::connections::systemBus, profileConnection, profilePath,
1534 thermalModeIface, "Current", *profile,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001535 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001536 if (ec)
1537 {
1538 BMCWEB_LOG_ERROR("Error patching profile{}", ec);
1539 messages::internalError(response->res);
1540 }
1541 });
James Feist73df0db2019-03-25 15:29:35 -07001542 }
1543
1544 for (auto& containerPair : configuration)
1545 {
1546 auto& container = containerPair.second;
1547 if (!container)
1548 {
1549 continue;
1550 }
James Feist6ee7f772020-02-06 16:25:27 -08001551
Ed Tanous02cad962022-06-30 16:50:15 -07001552 const std::string& type = containerPair.first;
James Feist73df0db2019-03-25 15:29:35 -07001553
Ed Tanous9e9b6042024-03-06 14:18:28 -08001554 for (auto& [name, value] : *container)
James Feist73df0db2019-03-25 15:29:35 -07001555 {
Potin Laicddbf3d2023-02-14 14:28:58 +08001556 std::string dbusObjName = name;
1557 std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
Ed Tanous62598e32023-07-17 17:06:25 -07001558 BMCWEB_LOG_DEBUG("looking for {}", name);
James Feist6ee7f772020-02-06 16:25:27 -08001559
Ed Tanous3544d2a2023-08-06 18:12:20 -07001560 auto pathItr = std::ranges::find_if(
1561 managedObj, [&dbusObjName](const auto& obj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001562 return obj.first.filename() == dbusObjName;
1563 });
Ed Tanousb9d36b42022-02-26 21:42:46 -08001564 dbus::utility::DBusPropertiesMap output;
James Feist73df0db2019-03-25 15:29:35 -07001565
1566 output.reserve(16); // The pid interface length
1567
1568 // determines if we're patching entity-manager or
1569 // creating a new object
1570 bool createNewObject = (pathItr == managedObj.end());
Ed Tanous62598e32023-07-17 17:06:25 -07001571 BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
James Feist6ee7f772020-02-06 16:25:27 -08001572
James Feist73df0db2019-03-25 15:29:35 -07001573 std::string iface;
Ed Tanousea2b6702022-03-07 16:48:38 -08001574 if (!createNewObject)
James Feist73df0db2019-03-25 15:29:35 -07001575 {
Potin Lai8be2b5b2022-11-22 13:27:16 +08001576 bool findInterface = false;
Ed Tanousea2b6702022-03-07 16:48:38 -08001577 for (const auto& interface : pathItr->second)
James Feist73df0db2019-03-25 15:29:35 -07001578 {
Ed Tanousea2b6702022-03-07 16:48:38 -08001579 if (interface.first == pidConfigurationIface)
1580 {
1581 if (type == "PidControllers" ||
1582 type == "FanControllers")
1583 {
1584 iface = pidConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001585 findInterface = true;
1586 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001587 }
1588 }
1589 else if (interface.first == pidZoneConfigurationIface)
1590 {
1591 if (type == "FanZones")
1592 {
PavanKumarIntelda393502024-03-15 05:47:02 +00001593 iface = pidZoneConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001594 findInterface = true;
1595 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001596 }
1597 }
1598 else if (interface.first == stepwiseConfigurationIface)
1599 {
1600 if (type == "StepwiseControllers")
1601 {
1602 iface = stepwiseConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001603 findInterface = true;
1604 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001605 }
1606 }
James Feist73df0db2019-03-25 15:29:35 -07001607 }
Potin Lai8be2b5b2022-11-22 13:27:16 +08001608
1609 // create new object if interface not found
1610 if (!findInterface)
1611 {
1612 createNewObject = true;
1613 }
James Feist73df0db2019-03-25 15:29:35 -07001614 }
James Feist6ee7f772020-02-06 16:25:27 -08001615
Ed Tanous9e9b6042024-03-06 14:18:28 -08001616 if (createNewObject && value == nullptr)
James Feist6ee7f772020-02-06 16:25:27 -08001617 {
Gunnar Mills4e0453b2020-07-08 14:00:30 -05001618 // can't delete a non-existent object
Ed Tanous9e9b6042024-03-06 14:18:28 -08001619 messages::propertyValueNotInList(response->res, value,
Ed Tanouse2616cc2022-06-27 12:45:55 -07001620 name);
James Feist6ee7f772020-02-06 16:25:27 -08001621 continue;
1622 }
1623
1624 std::string path;
1625 if (pathItr != managedObj.end())
1626 {
1627 path = pathItr->first.str;
1628 }
1629
Ed Tanous62598e32023-07-17 17:06:25 -07001630 BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
James Feiste69d9de2020-02-07 12:23:27 -08001631
1632 // arbitrary limit to avoid attacks
1633 constexpr const size_t controllerLimit = 500;
James Feist14b0b8d2020-02-12 11:52:07 -08001634 if (createNewObject && objectCount >= controllerLimit)
James Feiste69d9de2020-02-07 12:23:27 -08001635 {
1636 messages::resourceExhaustion(response->res, type);
1637 continue;
1638 }
Ed Tanousa170f272022-06-30 21:53:27 -07001639 std::string escaped = name;
1640 std::replace(escaped.begin(), escaped.end(), '_', ' ');
1641 output.emplace_back("Name", escaped);
James Feist73df0db2019-03-25 15:29:35 -07001642
1643 std::string chassis;
1644 CreatePIDRet ret = createPidInterface(
Ed Tanous9e9b6042024-03-06 14:18:28 -08001645 response, type, name, value, path, managedObj,
1646 createNewObject, output, chassis, currentProfile);
James Feist73df0db2019-03-25 15:29:35 -07001647 if (ret == CreatePIDRet::fail)
1648 {
1649 return;
1650 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001651 if (ret == CreatePIDRet::del)
James Feist73df0db2019-03-25 15:29:35 -07001652 {
1653 continue;
1654 }
1655
1656 if (!createNewObject)
1657 {
1658 for (const auto& property : output)
1659 {
Potin Lai7a696972023-11-09 12:18:20 +08001660 crow::connections::systemBus->async_method_call(
James Feist73df0db2019-03-25 15:29:35 -07001661 [response,
1662 propertyName{std::string(property.first)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001663 const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001664 if (ec)
1665 {
1666 BMCWEB_LOG_ERROR("Error patching {}: {}",
1667 propertyName, ec);
1668 messages::internalError(response->res);
1669 return;
1670 }
1671 messages::success(response->res);
1672 },
Potin Lai7a696972023-11-09 12:18:20 +08001673 "xyz.openbmc_project.EntityManager", path,
1674 "org.freedesktop.DBus.Properties", "Set", iface,
1675 property.first, property.second);
James Feist73df0db2019-03-25 15:29:35 -07001676 }
1677 }
1678 else
1679 {
1680 if (chassis.empty())
1681 {
Ed Tanous62598e32023-07-17 17:06:25 -07001682 BMCWEB_LOG_ERROR("Failed to get chassis from config");
Ed Tanousace85d62021-10-26 12:45:59 -07001683 messages::internalError(response->res);
James Feist73df0db2019-03-25 15:29:35 -07001684 return;
1685 }
1686
1687 bool foundChassis = false;
1688 for (const auto& obj : managedObj)
1689 {
Ed Tanous91f75ca2024-06-10 13:56:43 -07001690 if (obj.first.filename() == chassis)
James Feist73df0db2019-03-25 15:29:35 -07001691 {
1692 chassis = obj.first.str;
1693 foundChassis = true;
1694 break;
1695 }
1696 }
1697 if (!foundChassis)
1698 {
Ed Tanous62598e32023-07-17 17:06:25 -07001699 BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
James Feist73df0db2019-03-25 15:29:35 -07001700 messages::resourceMissingAtURI(
Ed Tanousace85d62021-10-26 12:45:59 -07001701 response->res,
Ed Tanousef4c65b2023-04-24 15:28:50 -07001702 boost::urls::format("/redfish/v1/Chassis/{}",
1703 chassis));
James Feist73df0db2019-03-25 15:29:35 -07001704 return;
1705 }
1706
1707 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001708 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001709 if (ec)
1710 {
1711 BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
1712 ec);
1713 messages::internalError(response->res);
1714 return;
1715 }
1716 messages::success(response->res);
1717 },
James Feist73df0db2019-03-25 15:29:35 -07001718 "xyz.openbmc_project.EntityManager", chassis,
1719 "xyz.openbmc_project.AddObject", "AddObject", output);
1720 }
1721 }
1722 }
1723 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001724
1725 ~SetPIDValues()
1726 {
1727 try
1728 {
1729 pidSetDone();
1730 }
1731 catch (...)
1732 {
Ed Tanous62598e32023-07-17 17:06:25 -07001733 BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -08001734 }
1735 }
1736
zhanghch058d1b46d2021-04-01 11:18:24 +08001737 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous9e9b6042024-03-06 14:18:28 -08001738 std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
James Feist73df0db2019-03-25 15:29:35 -07001739 configuration;
1740 std::optional<std::string> profile;
1741 dbus::utility::ManagedObjectType managedObj;
1742 std::vector<std::string> supportedProfiles;
1743 std::string currentProfile;
1744 std::string profileConnection;
1745 std::string profilePath;
James Feist14b0b8d2020-02-12 11:52:07 -08001746 size_t objectCount = 0;
James Feist73df0db2019-03-25 15:29:35 -07001747};
James Feist83ff9ab2018-08-31 10:18:24 -07001748
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001749/**
1750 * @brief Retrieves BMC manager location data over DBus
1751 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001752 * @param[in] asyncResp Shared pointer for completing asynchronous calls
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001753 * @param[in] connectionName - service name
1754 * @param[in] path - object path
1755 * @return none
1756 */
Ed Tanousac106bf2023-06-07 09:24:59 -07001757inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001758 const std::string& connectionName,
1759 const std::string& path)
1760{
Ed Tanous62598e32023-07-17 17:06:25 -07001761 BMCWEB_LOG_DEBUG("Get BMC manager Location data.");
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001762
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001763 sdbusplus::asio::getProperty<std::string>(
1764 *crow::connections::systemBus, connectionName, path,
1765 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanousac106bf2023-06-07 09:24:59 -07001766 [asyncResp](const boost::system::error_code& ec,
1767 const std::string& property) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001768 if (ec)
1769 {
1770 BMCWEB_LOG_DEBUG("DBUS response error for "
1771 "Location");
1772 messages::internalError(asyncResp->res);
1773 return;
1774 }
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001775
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001776 asyncResp->res
1777 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
1778 property;
1779 });
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001780}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001781// avoid name collision systems.hpp
1782inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001783 managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784{
Ed Tanous62598e32023-07-17 17:06:25 -07001785 BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time");
Ed Tanous52cc1122020-07-18 13:51:21 -07001786
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001787 sdbusplus::asio::getProperty<uint64_t>(
1788 *crow::connections::systemBus, "xyz.openbmc_project.State.BMC",
1789 "/xyz/openbmc_project/state/bmc0", "xyz.openbmc_project.State.BMC",
1790 "LastRebootTime",
Ed Tanousac106bf2023-06-07 09:24:59 -07001791 [asyncResp](const boost::system::error_code& ec,
1792 const uint64_t lastResetTime) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001793 if (ec)
1794 {
1795 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1796 return;
1797 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001798
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001799 // LastRebootTime is epoch time, in milliseconds
1800 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
1801 uint64_t lastResetTimeStamp = lastResetTime / 1000;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001802
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001803 // Convert to ISO 8601 standard
1804 asyncResp->res.jsonValue["LastResetTime"] =
1805 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1806 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001807}
1808
1809/**
1810 * @brief Set the running firmware image
1811 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001812 * @param[i,o] asyncResp - Async response object
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001813 * @param[i] runningFirmwareTarget - Image to make the running image
1814 *
1815 * @return void
1816 */
1817inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001818 setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001819 const std::string& runningFirmwareTarget)
1820{
1821 // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1822 std::string::size_type idPos = runningFirmwareTarget.rfind('/');
1823 if (idPos == std::string::npos)
1824 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001825 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001826 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001827 BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001828 return;
1829 }
1830 idPos++;
1831 if (idPos >= runningFirmwareTarget.size())
1832 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001833 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001834 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001835 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001836 return;
1837 }
1838 std::string firmwareId = runningFirmwareTarget.substr(idPos);
1839
1840 // Make sure the image is valid before setting priority
George Liu5eb468d2023-06-20 17:03:24 +08001841 sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
1842 dbus::utility::getManagedObjects(
1843 "xyz.openbmc_project.Software.BMC.Updater", objPath,
1844 [asyncResp, firmwareId, runningFirmwareTarget](
1845 const boost::system::error_code& ec,
1846 const dbus::utility::ManagedObjectType& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001847 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001848 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001849 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
Ed Tanousac106bf2023-06-07 09:24:59 -07001850 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001851 return;
1852 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001853
1854 if (subtree.empty())
1855 {
1856 BMCWEB_LOG_DEBUG("Can't find image!");
1857 messages::internalError(asyncResp->res);
1858 return;
1859 }
1860
1861 bool foundImage = false;
1862 for (const auto& object : subtree)
1863 {
1864 const std::string& path =
1865 static_cast<const std::string&>(object.first);
1866 std::size_t idPos2 = path.rfind('/');
1867
1868 if (idPos2 == std::string::npos)
1869 {
1870 continue;
1871 }
1872
1873 idPos2++;
1874 if (idPos2 >= path.size())
1875 {
1876 continue;
1877 }
1878
1879 if (path.substr(idPos2) == firmwareId)
1880 {
1881 foundImage = true;
1882 break;
1883 }
1884 }
1885
1886 if (!foundImage)
1887 {
1888 messages::propertyValueNotInList(
1889 asyncResp->res, runningFirmwareTarget, "@odata.id");
1890 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
1891 return;
1892 }
1893
1894 BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
1895 firmwareId);
1896
1897 // Only support Immediate
1898 // An addition could be a Redfish Setting like
1899 // ActiveSoftwareImageApplyTime and support OnReset
1900 sdbusplus::asio::setProperty(
1901 *crow::connections::systemBus,
1902 "xyz.openbmc_project.Software.BMC.Updater",
1903 "/xyz/openbmc_project/software/" + firmwareId,
1904 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
1905 static_cast<uint8_t>(0),
1906 [asyncResp](const boost::system::error_code& ec2) {
1907 if (ec2)
1908 {
1909 BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1910 messages::internalError(asyncResp->res);
1911 return;
1912 }
1913 doBMCGracefulRestart(asyncResp);
1914 });
George Liu5eb468d2023-06-20 17:03:24 +08001915 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001916}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001917
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001918inline void afterSetDateTime(
1919 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1920 const boost::system::error_code& ec, const sdbusplus::message_t& msg)
Ed Tanousc51afd52024-03-07 10:13:14 -08001921{
1922 if (ec)
1923 {
1924 BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1925 ec);
1926 const sd_bus_error* dbusError = msg.get_error();
1927 if (dbusError != nullptr)
1928 {
1929 std::string_view errorName(dbusError->name);
1930 if (errorName ==
1931 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1932 {
1933 BMCWEB_LOG_DEBUG("Setting conflict");
1934 messages::propertyValueConflict(
1935 asyncResp->res, "DateTime",
1936 "Managers/NetworkProtocol/NTPProcotolEnabled");
1937 return;
1938 }
1939 }
1940 messages::internalError(asyncResp->res);
1941 return;
1942 }
1943 asyncResp->res.result(boost::beast::http::status::no_content);
1944}
1945
1946inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1947 const std::string& datetime)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001948{
Ed Tanous62598e32023-07-17 17:06:25 -07001949 BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001950
Ed Tanousc2e32002023-01-07 22:05:08 -08001951 std::optional<redfish::time_utils::usSinceEpoch> us =
1952 redfish::time_utils::dateStringToEpoch(datetime);
1953 if (!us)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001954 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001955 messages::propertyValueFormatError(asyncResp->res, datetime,
1956 "DateTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001957 return;
1958 }
Ed Tanousc51afd52024-03-07 10:13:14 -08001959 // Set the absolute datetime
1960 bool relative = false;
1961 bool interactive = false;
1962 crow::connections::systemBus->async_method_call(
1963 [asyncResp](const boost::system::error_code& ec,
1964 const sdbusplus::message_t& msg) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001965 afterSetDateTime(asyncResp, ec, msg);
1966 },
Ed Tanousc51afd52024-03-07 10:13:14 -08001967 "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1968 "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1969 interactive);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001970}
1971
Ed Tanous75815e52022-10-05 17:21:13 -07001972inline void
1973 checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1974{
1975 sdbusplus::asio::getProperty<std::string>(
1976 *crow::connections::systemBus, "org.freedesktop.systemd1",
1977 "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
1978 "org.freedesktop.systemd1.Unit", "ActiveState",
1979 [asyncResp](const boost::system::error_code& ec,
1980 const std::string& val) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001981 if (!ec)
Ed Tanous75815e52022-10-05 17:21:13 -07001982 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001983 if (val == "active")
1984 {
1985 asyncResp->res.jsonValue["Status"]["Health"] =
1986 resource::Health::Critical;
1987 asyncResp->res.jsonValue["Status"]["State"] =
1988 resource::State::Quiesced;
1989 return;
1990 }
Ed Tanous75815e52022-10-05 17:21:13 -07001991 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001992 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
1993 asyncResp->res.jsonValue["Status"]["State"] =
1994 resource::State::Enabled;
1995 });
Ed Tanous75815e52022-10-05 17:21:13 -07001996}
1997
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001998inline void requestRoutesManager(App& app)
1999{
2000 std::string uuid = persistent_data::getConfig().systemUuid;
2001
Ed Tanous253f11b2024-05-16 09:38:31 -07002002 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002003 .privileges(redfish::privileges::getManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002004 .methods(
2005 boost::beast::http::verb::
2006 get)([&app,
2007 uuid](const crow::Request& req,
2008 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2009 const std::string& managerId) {
2010 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2011 {
2012 return;
2013 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002014
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002015 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2016 {
2017 messages::resourceNotFound(asyncResp->res, "Manager",
2018 managerId);
2019 return;
2020 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002021
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002022 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2023 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2024 asyncResp->res.jsonValue["@odata.type"] =
2025 "#Manager.v1_14_0.Manager";
2026 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
2027 asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
2028 asyncResp->res.jsonValue["Description"] =
2029 "Baseboard Management Controller";
2030 asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
Ed Tanous14766872022-03-15 10:44:42 -07002031
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002032 asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
2033 asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
2034 asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2035 asyncResp->res.jsonValue["Model"] =
2036 "OpenBmc"; // TODO(ed), get model
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002037
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002038 asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2039 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
Ed Tanous253f11b2024-05-16 09:38:31 -07002040 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002041 asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2042 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2043 BMCWEB_REDFISH_MANAGER_URI_NAME);
2044 asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2045 boost::urls::format(
2046 "/redfish/v1/Managers/{}/EthernetInterfaces",
2047 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002048
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002049 if constexpr (BMCWEB_VM_NBDPROXY)
Ed Tanous75815e52022-10-05 17:21:13 -07002050 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002051 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2052 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2053 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002054 }
2055
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002056 // default oem data
2057 nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
2058 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2059 oem["@odata.id"] =
2060 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2061 BMCWEB_REDFISH_MANAGER_URI_NAME);
2062 oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2063 oemOpenbmc["@odata.id"] =
2064 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2065 BMCWEB_REDFISH_MANAGER_URI_NAME);
2066
2067 nlohmann::json::object_t certificates;
2068 certificates["@odata.id"] = boost::urls::format(
2069 "/redfish/v1/Managers/{}/Truststore/Certificates",
2070 BMCWEB_REDFISH_MANAGER_URI_NAME);
2071 oemOpenbmc["Certificates"] = std::move(certificates);
2072
2073 // Manager.Reset (an action) can be many values, OpenBMC only
2074 // supports BMC reboot.
2075 nlohmann::json& managerReset =
2076 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2077 managerReset["target"] = boost::urls::format(
2078 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2079 BMCWEB_REDFISH_MANAGER_URI_NAME);
2080 managerReset["@Redfish.ActionInfo"] =
2081 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2082 BMCWEB_REDFISH_MANAGER_URI_NAME);
2083
2084 // ResetToDefaults (Factory Reset) has values like
2085 // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
2086 // on OpenBMC
2087 nlohmann::json& resetToDefaults =
2088 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2089 resetToDefaults["target"] = boost::urls::format(
2090 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2091 BMCWEB_REDFISH_MANAGER_URI_NAME);
2092 resetToDefaults["ResetType@Redfish.AllowableValues"] =
2093 nlohmann::json::array_t({"ResetAll"});
2094
2095 std::pair<std::string, std::string> redfishDateTimeOffset =
2096 redfish::time_utils::getDateTimeOffsetNow();
2097
2098 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2099 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2100 redfishDateTimeOffset.second;
2101
2102 // TODO (Gunnar): Remove these one day since moved to ComputerSystem
2103 // Still used by OCP profiles
2104 // https://github.com/opencomputeproject/OCP-Profiles/issues/23
2105 // Fill in SerialConsole info
2106 asyncResp->res.jsonValue["SerialConsole"]["ServiceEnabled"] = true;
2107 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2108 15;
2109 asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] =
2110 nlohmann::json::array_t({"IPMI", "SSH"});
2111 if constexpr (BMCWEB_KVM)
Ed Tanous002d39b2022-05-31 08:59:27 -07002112 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002113 // Fill in GraphicalConsole info
2114 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
2115 true;
2116 asyncResp->res
2117 .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
2118 asyncResp->res
2119 .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2120 nlohmann::json::array_t({"KVMIP"});
2121 }
2122 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2123 {
2124 asyncResp->res
2125 .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
2126
2127 nlohmann::json::array_t managerForServers;
2128 nlohmann::json::object_t manager;
2129 manager["@odata.id"] = std::format(
2130 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2131 managerForServers.emplace_back(std::move(manager));
2132
2133 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
2134 std::move(managerForServers);
Ed Tanous002d39b2022-05-31 08:59:27 -07002135 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002136
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002137 sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
2138 "FirmwareVersion", true);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002139
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002140 managerGetLastResetTime(asyncResp);
2141
2142 // ManagerDiagnosticData is added for all BMCs.
2143 nlohmann::json& managerDiagnosticData =
2144 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2145 managerDiagnosticData["@odata.id"] = boost::urls::format(
2146 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2147 BMCWEB_REDFISH_MANAGER_URI_NAME);
2148
2149 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
Ed Tanous002d39b2022-05-31 08:59:27 -07002150 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002151 auto pids = std::make_shared<GetPIDValues>(asyncResp);
2152 pids->run();
2153 }
2154
2155 getMainChassisId(asyncResp, [](const std::string& chassisId,
2156 const std::shared_ptr<
2157 bmcweb::AsyncResp>& aRsp) {
2158 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2159 1;
2160 nlohmann::json::array_t managerForChassis;
2161 nlohmann::json::object_t managerObj;
2162 boost::urls::url chassiUrl =
2163 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2164 managerObj["@odata.id"] = chassiUrl;
2165 managerForChassis.emplace_back(std::move(managerObj));
2166 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
2167 std::move(managerForChassis);
2168 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2169 chassiUrl;
2170 });
2171
2172 sdbusplus::asio::getProperty<double>(
2173 *crow::connections::systemBus, "org.freedesktop.systemd1",
2174 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
2175 "Progress",
2176 [asyncResp](const boost::system::error_code& ec, double val) {
2177 if (ec)
2178 {
2179 BMCWEB_LOG_ERROR("Error while getting progress");
2180 messages::internalError(asyncResp->res);
2181 return;
2182 }
2183 if (val < 1.0)
2184 {
2185 asyncResp->res.jsonValue["Status"]["Health"] =
2186 resource::Health::OK;
2187 asyncResp->res.jsonValue["Status"]["State"] =
2188 resource::State::Starting;
2189 return;
2190 }
2191 checkForQuiesced(asyncResp);
2192 });
2193
2194 constexpr std::array<std::string_view, 1> interfaces = {
2195 "xyz.openbmc_project.Inventory.Item.Bmc"};
2196 dbus::utility::getSubTree(
2197 "/xyz/openbmc_project/inventory", 0, interfaces,
2198 [asyncResp](
2199 const boost::system::error_code& ec,
2200 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2201 if (ec)
2202 {
2203 BMCWEB_LOG_DEBUG(
2204 "D-Bus response error on GetSubTree {}", ec);
2205 return;
2206 }
2207 if (subtree.empty())
2208 {
2209 BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
2210 return;
2211 }
2212 // Assume only 1 bmc D-Bus object
2213 // Throw an error if there is more than 1
2214 if (subtree.size() > 1)
2215 {
2216 BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
2217 messages::internalError(asyncResp->res);
2218 return;
2219 }
2220
2221 if (subtree[0].first.empty() ||
2222 subtree[0].second.size() != 1)
2223 {
2224 BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
2225 messages::internalError(asyncResp->res);
2226 return;
2227 }
2228
2229 const std::string& path = subtree[0].first;
2230 const std::string& connectionName =
2231 subtree[0].second[0].first;
2232
2233 for (const auto& interfaceName :
2234 subtree[0].second[0].second)
2235 {
2236 if (interfaceName ==
2237 "xyz.openbmc_project.Inventory.Decorator.Asset")
2238 {
2239 sdbusplus::asio::getAllProperties(
2240 *crow::connections::systemBus, connectionName,
2241 path,
2242 "xyz.openbmc_project.Inventory.Decorator.Asset",
2243 [asyncResp](
2244 const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002245 const dbus::utility::DBusPropertiesMap&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002246 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002247 if (ec2)
2248 {
2249 BMCWEB_LOG_DEBUG(
2250 "Can't get bmc asset!");
2251 return;
2252 }
2253
2254 const std::string* partNumber = nullptr;
2255 const std::string* serialNumber = nullptr;
2256 const std::string* manufacturer = nullptr;
2257 const std::string* model = nullptr;
2258 const std::string* sparePartNumber =
2259 nullptr;
2260
2261 const bool success =
2262 sdbusplus::unpackPropertiesNoThrow(
2263 dbus_utils::UnpackErrorPrinter(),
2264 propertiesList, "PartNumber",
2265 partNumber, "SerialNumber",
2266 serialNumber, "Manufacturer",
2267 manufacturer, "Model", model,
2268 "SparePartNumber", sparePartNumber);
2269
2270 if (!success)
2271 {
2272 messages::internalError(asyncResp->res);
2273 return;
2274 }
2275
2276 if (partNumber != nullptr)
2277 {
2278 asyncResp->res.jsonValue["PartNumber"] =
2279 *partNumber;
2280 }
2281
2282 if (serialNumber != nullptr)
2283 {
2284 asyncResp->res
2285 .jsonValue["SerialNumber"] =
2286 *serialNumber;
2287 }
2288
2289 if (manufacturer != nullptr)
2290 {
2291 asyncResp->res
2292 .jsonValue["Manufacturer"] =
2293 *manufacturer;
2294 }
2295
2296 if (model != nullptr)
2297 {
2298 asyncResp->res.jsonValue["Model"] =
2299 *model;
2300 }
2301
2302 if (sparePartNumber != nullptr)
2303 {
2304 asyncResp->res
2305 .jsonValue["SparePartNumber"] =
2306 *sparePartNumber;
2307 }
2308 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002309 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002310 else if (
2311 interfaceName ==
2312 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02002313 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002314 getLocation(asyncResp, connectionName, path);
Ed Tanous002d39b2022-05-31 08:59:27 -07002315 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002316 }
2317 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002318 });
2319
Ed Tanous253f11b2024-05-16 09:38:31 -07002320 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002321 .privileges(redfish::privileges::patchManager)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002322 .methods(boost::beast::http::verb::patch)(
2323 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002324 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2325 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002326 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2327 {
2328 return;
2329 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002330
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002331 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2332 {
2333 messages::resourceNotFound(asyncResp->res, "Manager",
2334 managerId);
2335 return;
2336 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002337
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002338 std::optional<std::string> activeSoftwareImageOdataId;
2339 std::optional<std::string> datetime;
2340 std::optional<nlohmann::json::object_t> pidControllers;
2341 std::optional<nlohmann::json::object_t> fanControllers;
2342 std::optional<nlohmann::json::object_t> fanZones;
2343 std::optional<nlohmann::json::object_t> stepwiseControllers;
2344 std::optional<std::string> profile;
Ed Tanous002d39b2022-05-31 08:59:27 -07002345
Myung Baeafc474a2024-10-09 00:53:29 -07002346 if (!json_util::readJsonPatch( //
2347 req, asyncResp->res, //
2348 "DateTime", datetime, //
2349 "Links/ActiveSoftwareImage/@odata.id",
2350 activeSoftwareImageOdataId, //
2351 "Oem/OpenBmc/Fan/FanControllers", fanControllers, //
2352 "Oem/OpenBmc/Fan/FanZones", fanZones, //
2353 "Oem/OpenBmc/Fan/PidControllers", pidControllers, //
2354 "Oem/OpenBmc/Fan/Profile", profile, //
2355 "Oem/OpenBmc/Fan/StepwiseControllers",
2356 stepwiseControllers //
2357 ))
2358 {
2359 return;
2360 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002361
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002362 if (pidControllers || fanControllers || fanZones ||
2363 stepwiseControllers || profile)
2364 {
2365 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
2366 {
2367 std::vector<
2368 std::pair<std::string,
Ed Tanous25b54db2024-04-17 15:40:31 -07002369 std::optional<nlohmann::json::object_t>>>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002370 configuration;
2371 if (pidControllers)
2372 {
2373 configuration.emplace_back(
2374 "PidControllers", std::move(pidControllers));
2375 }
2376 if (fanControllers)
2377 {
2378 configuration.emplace_back(
2379 "FanControllers", std::move(fanControllers));
2380 }
2381 if (fanZones)
2382 {
2383 configuration.emplace_back("FanZones",
2384 std::move(fanZones));
2385 }
2386 if (stepwiseControllers)
2387 {
2388 configuration.emplace_back(
2389 "StepwiseControllers",
2390 std::move(stepwiseControllers));
2391 }
2392 auto pid = std::make_shared<SetPIDValues>(
2393 asyncResp, std::move(configuration), profile);
2394 pid->run();
2395 }
2396 else
2397 {
2398 messages::propertyUnknown(asyncResp->res, "Oem");
2399 return;
2400 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002401 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002402
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002403 if (activeSoftwareImageOdataId)
2404 {
2405 setActiveFirmwareImage(asyncResp,
2406 *activeSoftwareImageOdataId);
2407 }
Ed Tanous9e9b6042024-03-06 14:18:28 -08002408
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002409 if (datetime)
2410 {
2411 setDateTime(asyncResp, *datetime);
2412 }
2413 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002414}
2415
2416inline void requestRoutesManagerCollection(App& app)
2417{
2418 BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
Ed Tanoused398212021-06-09 17:05:54 -07002419 .privileges(redfish::privileges::getManagerCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002420 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002421 [&app](const crow::Request& req,
2422 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002423 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2424 {
2425 return;
2426 }
2427 // Collections don't include the static data added by SubRoute
2428 // because it has a duplicate entry for members
2429 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
2430 asyncResp->res.jsonValue["@odata.type"] =
2431 "#ManagerCollection.ManagerCollection";
2432 asyncResp->res.jsonValue["Name"] = "Manager Collection";
2433 asyncResp->res.jsonValue["Members@odata.count"] = 1;
2434 nlohmann::json::array_t members;
2435 nlohmann::json& bmc = members.emplace_back();
2436 bmc["@odata.id"] = boost::urls::format(
2437 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2438 asyncResp->res.jsonValue["Members"] = std::move(members);
2439 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002440}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002441} // namespace redfish