blob: c4f9956cf5c58bfc1f586fa262ace9c6723aebea [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
216 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
217 resetType, "ResetToDefaultsType",
218 resetToDefaultsType))
219 {
220 BMCWEB_LOG_DEBUG("Missing property ResetType.");
221
222 messages::actionParameterMissing(
223 asyncResp->res, "ResetToDefaults", "ResetType");
224 return;
225 }
226
227 if (resetToDefaultsType && !resetType)
228 {
229 BMCWEB_LOG_WARNING(
230 "Using deprecated ResetToDefaultsType, should be ResetType."
231 "Support for the ResetToDefaultsType will be dropped in 2Q24");
232 resetType = resetToDefaultsType;
233 }
234
235 if (resetType != "ResetAll")
236 {
237 BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}",
238 *resetType);
239 messages::actionParameterNotSupported(asyncResp->res,
240 *resetType, "ResetType");
241 return;
242 }
243
244 crow::connections::systemBus->async_method_call(
245 [asyncResp](const boost::system::error_code& ec) {
246 if (ec)
247 {
248 BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec);
249 messages::internalError(asyncResp->res);
250 return;
251 }
252 // Factory Reset doesn't actually happen until a reboot
253 // Can't erase what the BMC is running on
254 doBMCGracefulRestart(asyncResp);
255 },
256 "xyz.openbmc_project.Software.BMC.Updater",
257 "/xyz/openbmc_project/software",
258 "xyz.openbmc_project.Common.FactoryReset", "Reset");
259 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700260}
Gunnar Mills3e40fc72020-05-19 19:18:17 -0500261
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530262/**
263 * ManagerResetActionInfo derived class for delivering Manager
264 * ResetType AllowableValues using ResetInfo schema.
265 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700266inline void requestRoutesManagerResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530267{
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530268 /**
269 * Functions triggers appropriate requests on DBus
270 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700271
Ed Tanous253f11b2024-05-16 09:38:31 -0700272 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700273 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700274 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700275 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700276 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
277 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400278 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
279 {
280 return;
281 }
Ed Tanous14766872022-03-15 10:44:42 -0700282
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400283 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
284 {
285 messages::resourceNotFound(asyncResp->res, "Manager",
286 managerId);
287 return;
288 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700289
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400290 asyncResp->res.jsonValue["@odata.type"] =
291 "#ActionInfo.v1_1_2.ActionInfo";
292 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
293 "/redfish/v1/Managers/{}/ResetActionInfo",
294 BMCWEB_REDFISH_MANAGER_URI_NAME);
295 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
296 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
297 nlohmann::json::object_t parameter;
298 parameter["Name"] = "ResetType";
299 parameter["Required"] = true;
300 parameter["DataType"] = action_info::ParameterTypes::String;
Ed Tanous14766872022-03-15 10:44:42 -0700301
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400302 nlohmann::json::array_t allowableValues;
303 allowableValues.emplace_back("GracefulRestart");
304 allowableValues.emplace_back("ForceRestart");
305 parameter["AllowableValues"] = std::move(allowableValues);
Ed Tanous14766872022-03-15 10:44:42 -0700306
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400307 nlohmann::json::array_t parameters;
308 parameters.emplace_back(std::move(parameter));
Ed Tanous14766872022-03-15 10:44:42 -0700309
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400310 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
311 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700312}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530313
James Feist5b4aa862018-08-16 14:07:01 -0700314static constexpr const char* objectManagerIface =
315 "org.freedesktop.DBus.ObjectManager";
316static constexpr const char* pidConfigurationIface =
317 "xyz.openbmc_project.Configuration.Pid";
318static constexpr const char* pidZoneConfigurationIface =
319 "xyz.openbmc_project.Configuration.Pid.Zone";
James Feistb7a08d02018-12-11 14:55:37 -0800320static constexpr const char* stepwiseConfigurationIface =
321 "xyz.openbmc_project.Configuration.Stepwise";
James Feist73df0db2019-03-25 15:29:35 -0700322static constexpr const char* thermalModeIface =
323 "xyz.openbmc_project.Control.ThermalMode";
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100324
zhanghch058d1b46d2021-04-01 11:18:24 +0800325inline void
326 asyncPopulatePid(const std::string& connection, const std::string& path,
327 const std::string& currentProfile,
328 const std::vector<std::string>& supportedProfiles,
329 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
James Feist5b4aa862018-08-16 14:07:01 -0700330{
George Liu5eb468d2023-06-20 17:03:24 +0800331 sdbusplus::message::object_path objPath(path);
332 dbus::utility::getManagedObjects(
333 connection, objPath,
James Feist73df0db2019-03-25 15:29:35 -0700334 [asyncResp, currentProfile, supportedProfiles](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800335 const boost::system::error_code& ec,
James Feist73df0db2019-03-25 15:29:35 -0700336 const dbus::utility::ManagedObjectType& managedObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400337 if (ec)
James Feist5b4aa862018-08-16 14:07:01 -0700338 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400339 BMCWEB_LOG_ERROR("{}", ec);
340 messages::internalError(asyncResp->res);
341 return;
342 }
343 nlohmann::json& configRoot =
344 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
345 nlohmann::json& fans = configRoot["FanControllers"];
346 fans["@odata.type"] =
347 "#OpenBMCManager.v1_0_0.Manager.FanControllers";
348 fans["@odata.id"] = boost::urls::format(
349 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
350 BMCWEB_REDFISH_MANAGER_URI_NAME);
351
352 nlohmann::json& pids = configRoot["PidControllers"];
353 pids["@odata.type"] =
354 "#OpenBMCManager.v1_0_0.Manager.PidControllers";
355 pids["@odata.id"] = boost::urls::format(
356 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
357 BMCWEB_REDFISH_MANAGER_URI_NAME);
358
359 nlohmann::json& stepwise = configRoot["StepwiseControllers"];
360 stepwise["@odata.type"] =
361 "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
362 stepwise["@odata.id"] = boost::urls::format(
363 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
364 BMCWEB_REDFISH_MANAGER_URI_NAME);
365
366 nlohmann::json& zones = configRoot["FanZones"];
367 zones["@odata.id"] = boost::urls::format(
368 "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
369 BMCWEB_REDFISH_MANAGER_URI_NAME);
370 zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
371 configRoot["@odata.id"] =
372 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
373 BMCWEB_REDFISH_MANAGER_URI_NAME);
374 configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
375 configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
376
377 if (!currentProfile.empty())
378 {
379 configRoot["Profile"] = currentProfile;
380 }
381 BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
382
383 for (const auto& pathPair : managedObj)
384 {
385 for (const auto& intfPair : pathPair.second)
James Feist5b4aa862018-08-16 14:07:01 -0700386 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400387 if (intfPair.first != pidConfigurationIface &&
388 intfPair.first != pidZoneConfigurationIface &&
389 intfPair.first != stepwiseConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 {
391 continue;
392 }
393
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400394 std::string name;
395
396 for (const std::pair<std::string,
397 dbus::utility::DbusVariantType>&
398 propPair : intfPair.second)
399 {
400 if (propPair.first == "Name")
401 {
402 const std::string* namePtr =
403 std::get_if<std::string>(&propPair.second);
404 if (namePtr == nullptr)
405 {
406 BMCWEB_LOG_ERROR("Pid Name Field illegal");
407 messages::internalError(asyncResp->res);
408 return;
409 }
410 name = *namePtr;
411 dbus::utility::escapePathForDbus(name);
412 }
413 else if (propPair.first == "Profiles")
414 {
415 const std::vector<std::string>* profiles =
416 std::get_if<std::vector<std::string>>(
417 &propPair.second);
418 if (profiles == nullptr)
419 {
420 BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
421 messages::internalError(asyncResp->res);
422 return;
423 }
424 if (std::find(profiles->begin(), profiles->end(),
425 currentProfile) == profiles->end())
426 {
427 BMCWEB_LOG_INFO(
428 "{} not supported in current profile",
429 name);
430 continue;
431 }
432 }
433 }
434 nlohmann::json* config = nullptr;
435 const std::string* classPtr = nullptr;
436
437 for (const std::pair<std::string,
438 dbus::utility::DbusVariantType>&
439 propPair : intfPair.second)
440 {
441 if (propPair.first == "Class")
442 {
443 classPtr =
444 std::get_if<std::string>(&propPair.second);
445 }
446 }
447
448 boost::urls::url url(
449 boost::urls::format("/redfish/v1/Managers/{}",
450 BMCWEB_REDFISH_MANAGER_URI_NAME));
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 if (intfPair.first == pidZoneConfigurationIface)
452 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400453 std::string chassis;
454 if (!dbus::utility::getNthStringFromPath(
455 pathPair.first.str, 5, chassis))
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400457 chassis = "#IllegalValue";
458 }
459 nlohmann::json& zone = zones[name];
460 zone["Chassis"]["@odata.id"] = boost::urls::format(
461 "/redfish/v1/Chassis/{}", chassis);
462 url.set_fragment(
463 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
464 .to_string());
465 zone["@odata.id"] = std::move(url);
466 zone["@odata.type"] =
467 "#OpenBMCManager.v1_0_0.Manager.FanZone";
468 config = &zone;
469 }
470
471 else if (intfPair.first == stepwiseConfigurationIface)
472 {
473 if (classPtr == nullptr)
474 {
475 BMCWEB_LOG_ERROR("Pid Class Field illegal");
Ed Tanous002d39b2022-05-31 08:59:27 -0700476 messages::internalError(asyncResp->res);
477 return;
478 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700479
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400480 nlohmann::json& controller = stepwise[name];
481 config = &controller;
482 url.set_fragment(
483 ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
484 name)
485 .to_string());
486 controller["@odata.id"] = std::move(url);
487 controller["@odata.type"] =
488 "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700489
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400490 controller["Direction"] = *classPtr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700491 }
James Feistb7a08d02018-12-11 14:55:37 -0800492
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 // pid and fans are off the same configuration
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400494 else if (intfPair.first == pidConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700495 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400496 if (classPtr == nullptr)
James Feistb7a08d02018-12-11 14:55:37 -0800497 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400498 BMCWEB_LOG_ERROR("Pid Class Field illegal");
499 messages::internalError(asyncResp->res);
500 return;
James Feist5b4aa862018-08-16 14:07:01 -0700501 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400502 bool isFan = *classPtr == "fan";
503 nlohmann::json& element =
504 isFan ? fans[name] : pids[name];
505 config = &element;
506 if (isFan)
James Feist5b4aa862018-08-16 14:07:01 -0700507 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400508 url.set_fragment(
509 ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
510 name)
511 .to_string());
512 element["@odata.id"] = std::move(url);
513 element["@odata.type"] =
514 "#OpenBMCManager.v1_0_0.Manager.FanController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700515 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400516 else
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400518 url.set_fragment(
519 ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
520 name)
521 .to_string());
522 element["@odata.id"] = std::move(url);
523 element["@odata.type"] =
524 "#OpenBMCManager.v1_0_0.Manager.PidController";
Ed Tanous002d39b2022-05-31 08:59:27 -0700525 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400526 }
527 else
528 {
529 BMCWEB_LOG_ERROR("Unexpected configuration");
530 messages::internalError(asyncResp->res);
531 return;
532 }
533
534 // used for making maps out of 2 vectors
535 const std::vector<double>* keys = nullptr;
536 const std::vector<double>* values = nullptr;
537
538 for (const auto& propertyPair : intfPair.second)
539 {
540 if (propertyPair.first == "Type" ||
541 propertyPair.first == "Class" ||
542 propertyPair.first == "Name")
543 {
544 continue;
545 }
546
547 // zones
548 if (intfPair.first == pidZoneConfigurationIface)
Ed Tanous002d39b2022-05-31 08:59:27 -0700549 {
550 const double* ptr =
551 std::get_if<double>(&propertyPair.second);
552 if (ptr == nullptr)
553 {
Ed Tanous62598e32023-07-17 17:06:25 -0700554 BMCWEB_LOG_ERROR("Field Illegal {}",
555 propertyPair.first);
Ed Tanous002d39b2022-05-31 08:59:27 -0700556 messages::internalError(asyncResp->res);
557 return;
558 }
559 (*config)[propertyPair.first] = *ptr;
James Feist5b4aa862018-08-16 14:07:01 -0700560 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400561
562 if (intfPair.first == stepwiseConfigurationIface)
563 {
564 if (propertyPair.first == "Reading" ||
565 propertyPair.first == "Output")
566 {
567 const std::vector<double>* ptr =
568 std::get_if<std::vector<double>>(
569 &propertyPair.second);
570
571 if (ptr == nullptr)
572 {
573 BMCWEB_LOG_ERROR("Field Illegal {}",
574 propertyPair.first);
575 messages::internalError(asyncResp->res);
576 return;
577 }
578
579 if (propertyPair.first == "Reading")
580 {
581 keys = ptr;
582 }
583 else
584 {
585 values = ptr;
586 }
587 if (keys != nullptr && values != nullptr)
588 {
589 if (keys->size() != values->size())
590 {
591 BMCWEB_LOG_ERROR(
592 "Reading and Output size don't match ");
593 messages::internalError(asyncResp->res);
594 return;
595 }
596 nlohmann::json& steps = (*config)["Steps"];
597 steps = nlohmann::json::array();
598 for (size_t ii = 0; ii < keys->size(); ii++)
599 {
600 nlohmann::json::object_t step;
601 step["Target"] = (*keys)[ii];
602 step["Output"] = (*values)[ii];
603 steps.emplace_back(std::move(step));
604 }
605 }
606 }
607 if (propertyPair.first == "NegativeHysteresis" ||
608 propertyPair.first == "PositiveHysteresis")
609 {
610 const double* ptr =
611 std::get_if<double>(&propertyPair.second);
612 if (ptr == nullptr)
613 {
614 BMCWEB_LOG_ERROR("Field Illegal {}",
615 propertyPair.first);
616 messages::internalError(asyncResp->res);
617 return;
618 }
619 (*config)[propertyPair.first] = *ptr;
620 }
621 }
622
623 // pid and fans are off the same configuration
624 if (intfPair.first == pidConfigurationIface ||
625 intfPair.first == stepwiseConfigurationIface)
626 {
627 if (propertyPair.first == "Zones")
628 {
629 const std::vector<std::string>* inputs =
630 std::get_if<std::vector<std::string>>(
631 &propertyPair.second);
632
633 if (inputs == nullptr)
634 {
635 BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
636 messages::internalError(asyncResp->res);
637 return;
638 }
639 auto& data = (*config)[propertyPair.first];
640 data = nlohmann::json::array();
641 for (std::string itemCopy : *inputs)
642 {
643 dbus::utility::escapePathForDbus(itemCopy);
644 nlohmann::json::object_t input;
645 boost::urls::url managerUrl =
646 boost::urls::format(
647 "/redfish/v1/Managers/{}#{}",
648 BMCWEB_REDFISH_MANAGER_URI_NAME,
649 ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
650 itemCopy)
651 .to_string());
652 input["@odata.id"] = std::move(managerUrl);
653 data.emplace_back(std::move(input));
654 }
655 }
656 // todo(james): may never happen, but this
657 // assumes configuration data referenced in the
658 // PID config is provided by the same daemon, we
659 // could add another loop to cover all cases,
660 // but I'm okay kicking this can down the road a
661 // bit
662
663 else if (propertyPair.first == "Inputs" ||
664 propertyPair.first == "Outputs")
665 {
666 auto& data = (*config)[propertyPair.first];
667 const std::vector<std::string>* inputs =
668 std::get_if<std::vector<std::string>>(
669 &propertyPair.second);
670
671 if (inputs == nullptr)
672 {
673 BMCWEB_LOG_ERROR("Field Illegal {}",
674 propertyPair.first);
675 messages::internalError(asyncResp->res);
676 return;
677 }
678 data = *inputs;
679 }
680 else if (propertyPair.first == "SetPointOffset")
681 {
682 const std::string* ptr =
683 std::get_if<std::string>(
684 &propertyPair.second);
685
686 if (ptr == nullptr)
687 {
688 BMCWEB_LOG_ERROR("Field Illegal {}",
689 propertyPair.first);
690 messages::internalError(asyncResp->res);
691 return;
692 }
693 // translate from dbus to redfish
694 if (*ptr == "WarningHigh")
695 {
696 (*config)["SetPointOffset"] =
697 "UpperThresholdNonCritical";
698 }
699 else if (*ptr == "WarningLow")
700 {
701 (*config)["SetPointOffset"] =
702 "LowerThresholdNonCritical";
703 }
704 else if (*ptr == "CriticalHigh")
705 {
706 (*config)["SetPointOffset"] =
707 "UpperThresholdCritical";
708 }
709 else if (*ptr == "CriticalLow")
710 {
711 (*config)["SetPointOffset"] =
712 "LowerThresholdCritical";
713 }
714 else
715 {
716 BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
717 messages::internalError(asyncResp->res);
718 return;
719 }
720 }
721 // doubles
722 else if (propertyPair.first ==
723 "FFGainCoefficient" ||
724 propertyPair.first == "FFOffCoefficient" ||
725 propertyPair.first == "ICoefficient" ||
726 propertyPair.first == "ILimitMax" ||
727 propertyPair.first == "ILimitMin" ||
728 propertyPair.first ==
729 "PositiveHysteresis" ||
730 propertyPair.first ==
731 "NegativeHysteresis" ||
732 propertyPair.first == "OutLimitMax" ||
733 propertyPair.first == "OutLimitMin" ||
734 propertyPair.first == "PCoefficient" ||
735 propertyPair.first == "SetPoint" ||
736 propertyPair.first == "SlewNeg" ||
737 propertyPair.first == "SlewPos")
738 {
739 const double* ptr =
740 std::get_if<double>(&propertyPair.second);
741 if (ptr == nullptr)
742 {
743 BMCWEB_LOG_ERROR("Field Illegal {}",
744 propertyPair.first);
745 messages::internalError(asyncResp->res);
746 return;
747 }
748 (*config)[propertyPair.first] = *ptr;
749 }
750 }
James Feist5b4aa862018-08-16 14:07:01 -0700751 }
752 }
753 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400754 });
James Feist5b4aa862018-08-16 14:07:01 -0700755}
Jennifer Leeca537922018-08-10 10:07:30 -0700756
James Feist83ff9ab2018-08-31 10:18:24 -0700757enum class CreatePIDRet
758{
759 fail,
760 del,
761 patch
762};
763
zhanghch058d1b46d2021-04-01 11:18:24 +0800764inline bool
765 getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800766 std::vector<nlohmann::json::object_t>& config,
zhanghch058d1b46d2021-04-01 11:18:24 +0800767 std::vector<std::string>& zones)
James Feist5f2caae2018-12-12 14:08:25 -0800768{
James Feistb6baeaa2019-02-21 10:41:40 -0800769 if (config.empty())
770 {
Ed Tanous62598e32023-07-17 17:06:25 -0700771 BMCWEB_LOG_ERROR("Empty Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700772 messages::propertyValueFormatError(response->res, config, "Zones");
James Feistb6baeaa2019-02-21 10:41:40 -0800773 return false;
774 }
James Feist5f2caae2018-12-12 14:08:25 -0800775 for (auto& odata : config)
776 {
777 std::string path;
Ed Tanous9e9b6042024-03-06 14:18:28 -0800778 if (!redfish::json_util::readJsonObject(odata, response->res,
779 "@odata.id", path))
James Feist5f2caae2018-12-12 14:08:25 -0800780 {
781 return false;
782 }
783 std::string input;
James Feist61adbda2019-03-25 13:03:51 -0700784
785 // 8 below comes from
786 // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
787 // 0 1 2 3 4 5 6 7 8
788 if (!dbus::utility::getNthStringFromPath(path, 8, input))
James Feist5f2caae2018-12-12 14:08:25 -0800789 {
Ed Tanous62598e32023-07-17 17:06:25 -0700790 BMCWEB_LOG_ERROR("Got invalid path {}", path);
791 BMCWEB_LOG_ERROR("Illegal Type Zones");
Ed Tanousf818b042022-06-27 13:17:35 -0700792 messages::propertyValueFormatError(response->res, odata, "Zones");
James Feist5f2caae2018-12-12 14:08:25 -0800793 return false;
794 }
Ed Tanousa170f272022-06-30 21:53:27 -0700795 std::replace(input.begin(), input.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -0800796 zones.emplace_back(std::move(input));
797 }
798 return true;
799}
800
Ed Tanous711ac7a2021-12-20 09:34:41 -0800801inline const dbus::utility::ManagedObjectType::value_type*
James Feist73df0db2019-03-25 15:29:35 -0700802 findChassis(const dbus::utility::ManagedObjectType& managedObj,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800803 std::string_view value, std::string& chassis)
James Feistb6baeaa2019-02-21 10:41:40 -0800804{
Ed Tanous62598e32023-07-17 17:06:25 -0700805 BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
James Feistb6baeaa2019-02-21 10:41:40 -0800806
Ed Tanous9e9b6042024-03-06 14:18:28 -0800807 std::string escaped(value);
Yaswanth Reddy M6ce82fa2023-03-10 07:29:45 +0000808 std::replace(escaped.begin(), escaped.end(), ' ', '_');
James Feistb6baeaa2019-02-21 10:41:40 -0800809 escaped = "/" + escaped;
Ed Tanous3544d2a2023-08-06 18:12:20 -0700810 auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
Ed Tanous18f8f602023-07-18 10:07:23 -0700811 if (obj.first.str.ends_with(escaped))
Ed Tanous002d39b2022-05-31 08:59:27 -0700812 {
Ed Tanous62598e32023-07-17 17:06:25 -0700813 BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700814 return true;
815 }
816 return false;
817 });
James Feistb6baeaa2019-02-21 10:41:40 -0800818
819 if (it == managedObj.end())
820 {
James Feist73df0db2019-03-25 15:29:35 -0700821 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800822 }
823 // 5 comes from <chassis-name> being the 5th element
824 // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
James Feist73df0db2019-03-25 15:29:35 -0700825 if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
826 {
827 return &(*it);
828 }
829
830 return nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800831}
832
Ed Tanous23a21a12020-07-25 04:45:05 +0000833inline CreatePIDRet createPidInterface(
zhanghch058d1b46d2021-04-01 11:18:24 +0800834 const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
Ed Tanous9e9b6042024-03-06 14:18:28 -0800835 std::string_view name, nlohmann::json& jsonValue, const std::string& path,
James Feist83ff9ab2018-08-31 10:18:24 -0700836 const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800837 dbus::utility::DBusPropertiesMap& output, std::string& chassis,
838 const std::string& profile)
James Feist83ff9ab2018-08-31 10:18:24 -0700839{
James Feist5f2caae2018-12-12 14:08:25 -0800840 // common deleter
Ed Tanous9e9b6042024-03-06 14:18:28 -0800841 if (jsonValue == nullptr)
James Feist5f2caae2018-12-12 14:08:25 -0800842 {
843 std::string iface;
844 if (type == "PidControllers" || type == "FanControllers")
845 {
846 iface = pidConfigurationIface;
847 }
848 else if (type == "FanZones")
849 {
850 iface = pidZoneConfigurationIface;
851 }
852 else if (type == "StepwiseControllers")
853 {
854 iface = stepwiseConfigurationIface;
855 }
856 else
857 {
Ed Tanous62598e32023-07-17 17:06:25 -0700858 BMCWEB_LOG_ERROR("Illegal Type {}", type);
James Feist5f2caae2018-12-12 14:08:25 -0800859 messages::propertyUnknown(response->res, type);
860 return CreatePIDRet::fail;
861 }
James Feist6ee7f772020-02-06 16:25:27 -0800862
Ed Tanous62598e32023-07-17 17:06:25 -0700863 BMCWEB_LOG_DEBUG("del {} {}", path, iface);
James Feist5f2caae2018-12-12 14:08:25 -0800864 // delete interface
865 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800866 [response, path](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400867 if (ec)
868 {
869 BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
870 messages::internalError(response->res);
871 return;
872 }
873 messages::success(response->res);
874 },
James Feist5f2caae2018-12-12 14:08:25 -0800875 "xyz.openbmc_project.EntityManager", path, iface, "Delete");
876 return CreatePIDRet::del;
877 }
878
Ed Tanous711ac7a2021-12-20 09:34:41 -0800879 const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
James Feistb6baeaa2019-02-21 10:41:40 -0800880 if (!createNewObject)
881 {
882 // if we aren't creating a new object, we should be able to find it on
883 // d-bus
Ed Tanous9e9b6042024-03-06 14:18:28 -0800884 managedItem = findChassis(managedObj, name, chassis);
James Feist73df0db2019-03-25 15:29:35 -0700885 if (managedItem == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -0800886 {
Ed Tanous62598e32023-07-17 17:06:25 -0700887 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousef4c65b2023-04-24 15:28:50 -0700888 messages::invalidObject(
889 response->res,
890 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -0800891 return CreatePIDRet::fail;
892 }
893 }
894
Ed Tanous26f69762022-01-25 09:49:11 -0800895 if (!profile.empty() &&
James Feist73df0db2019-03-25 15:29:35 -0700896 (type == "PidControllers" || type == "FanControllers" ||
897 type == "StepwiseControllers"))
898 {
899 if (managedItem == nullptr)
900 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800901 output.emplace_back("Profiles", std::vector<std::string>{profile});
James Feist73df0db2019-03-25 15:29:35 -0700902 }
903 else
904 {
905 std::string interface;
906 if (type == "StepwiseControllers")
907 {
908 interface = stepwiseConfigurationIface;
909 }
910 else
911 {
912 interface = pidConfigurationIface;
913 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800914 bool ifaceFound = false;
915 for (const auto& iface : managedItem->second)
916 {
917 if (iface.first == interface)
918 {
919 ifaceFound = true;
920 for (const auto& prop : iface.second)
921 {
922 if (prop.first == "Profiles")
923 {
924 const std::vector<std::string>* curProfiles =
925 std::get_if<std::vector<std::string>>(
926 &(prop.second));
927 if (curProfiles == nullptr)
928 {
Ed Tanous62598e32023-07-17 17:06:25 -0700929 BMCWEB_LOG_ERROR(
930 "Illegal profiles in managed object");
Ed Tanous711ac7a2021-12-20 09:34:41 -0800931 messages::internalError(response->res);
932 return CreatePIDRet::fail;
933 }
934 if (std::find(curProfiles->begin(),
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400935 curProfiles->end(), profile) ==
936 curProfiles->end())
Ed Tanous711ac7a2021-12-20 09:34:41 -0800937 {
938 std::vector<std::string> newProfiles =
939 *curProfiles;
940 newProfiles.push_back(profile);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800941 output.emplace_back("Profiles", newProfiles);
Ed Tanous711ac7a2021-12-20 09:34:41 -0800942 }
943 }
944 }
945 }
946 }
947
948 if (!ifaceFound)
James Feist73df0db2019-03-25 15:29:35 -0700949 {
Ed Tanous62598e32023-07-17 17:06:25 -0700950 BMCWEB_LOG_ERROR("Failed to find interface in managed object");
James Feist73df0db2019-03-25 15:29:35 -0700951 messages::internalError(response->res);
952 return CreatePIDRet::fail;
953 }
James Feist73df0db2019-03-25 15:29:35 -0700954 }
955 }
956
James Feist83ff9ab2018-08-31 10:18:24 -0700957 if (type == "PidControllers" || type == "FanControllers")
958 {
959 if (createNewObject)
960 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800961 output.emplace_back("Class",
962 type == "PidControllers" ? "temp" : "fan");
963 output.emplace_back("Type", "Pid");
James Feist83ff9ab2018-08-31 10:18:24 -0700964 }
James Feist5f2caae2018-12-12 14:08:25 -0800965
Ed Tanous9e9b6042024-03-06 14:18:28 -0800966 std::optional<std::vector<nlohmann::json::object_t>> zones;
James Feist5f2caae2018-12-12 14:08:25 -0800967 std::optional<std::vector<std::string>> inputs;
968 std::optional<std::vector<std::string>> outputs;
969 std::map<std::string, std::optional<double>> doubles;
James Feistb943aae2019-07-11 16:33:56 -0700970 std::optional<std::string> setpointOffset;
James Feist5f2caae2018-12-12 14:08:25 -0800971 if (!redfish::json_util::readJson(
Ed Tanous9e9b6042024-03-06 14:18:28 -0800972 jsonValue, response->res, "Inputs", inputs, "Outputs", outputs,
James Feist5f2caae2018-12-12 14:08:25 -0800973 "Zones", zones, "FFGainCoefficient",
974 doubles["FFGainCoefficient"], "FFOffCoefficient",
975 doubles["FFOffCoefficient"], "ICoefficient",
976 doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"],
977 "ILimitMin", doubles["ILimitMin"], "OutLimitMax",
978 doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"],
979 "PCoefficient", doubles["PCoefficient"], "SetPoint",
James Feistb943aae2019-07-11 16:33:56 -0700980 doubles["SetPoint"], "SetPointOffset", setpointOffset,
981 "SlewNeg", doubles["SlewNeg"], "SlewPos", doubles["SlewPos"],
982 "PositiveHysteresis", doubles["PositiveHysteresis"],
983 "NegativeHysteresis", doubles["NegativeHysteresis"]))
James Feist83ff9ab2018-08-31 10:18:24 -0700984 {
James Feist5f2caae2018-12-12 14:08:25 -0800985 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -0700986 }
James Feist5f2caae2018-12-12 14:08:25 -0800987 if (zones)
James Feist83ff9ab2018-08-31 10:18:24 -0700988 {
James Feist5f2caae2018-12-12 14:08:25 -0800989 std::vector<std::string> zonesStr;
990 if (!getZonesFromJsonReq(response, *zones, zonesStr))
James Feist83ff9ab2018-08-31 10:18:24 -0700991 {
Ed Tanous62598e32023-07-17 17:06:25 -0700992 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -0800993 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -0700994 }
James Feistb6baeaa2019-02-21 10:41:40 -0800995 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -0800996 findChassis(managedObj, zonesStr[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -0800997 {
Ed Tanous62598e32023-07-17 17:06:25 -0700998 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -0700999 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001000 response->res,
1001 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001002 return CreatePIDRet::fail;
1003 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001004 output.emplace_back("Zones", std::move(zonesStr));
James Feist5f2caae2018-12-12 14:08:25 -08001005 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001006
1007 if (inputs)
James Feist5f2caae2018-12-12 14:08:25 -08001008 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001009 for (std::string& value : *inputs)
James Feist83ff9ab2018-08-31 10:18:24 -07001010 {
Ed Tanousafb9ee02022-12-21 11:59:17 -08001011 std::replace(value.begin(), value.end(), '_', ' ');
James Feist83ff9ab2018-08-31 10:18:24 -07001012 }
Ed Tanousafb9ee02022-12-21 11:59:17 -08001013 output.emplace_back("Inputs", *inputs);
1014 }
1015
1016 if (outputs)
1017 {
1018 for (std::string& value : *outputs)
1019 {
1020 std::replace(value.begin(), value.end(), '_', ' ');
1021 }
1022 output.emplace_back("Outputs", *outputs);
James Feist5f2caae2018-12-12 14:08:25 -08001023 }
James Feist83ff9ab2018-08-31 10:18:24 -07001024
James Feistb943aae2019-07-11 16:33:56 -07001025 if (setpointOffset)
1026 {
1027 // translate between redfish and dbus names
1028 if (*setpointOffset == "UpperThresholdNonCritical")
1029 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001030 output.emplace_back("SetPointOffset", "WarningLow");
James Feistb943aae2019-07-11 16:33:56 -07001031 }
1032 else if (*setpointOffset == "LowerThresholdNonCritical")
1033 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001034 output.emplace_back("SetPointOffset", "WarningHigh");
James Feistb943aae2019-07-11 16:33:56 -07001035 }
1036 else if (*setpointOffset == "LowerThresholdCritical")
1037 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001038 output.emplace_back("SetPointOffset", "CriticalLow");
James Feistb943aae2019-07-11 16:33:56 -07001039 }
1040 else if (*setpointOffset == "UpperThresholdCritical")
1041 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001042 output.emplace_back("SetPointOffset", "CriticalHigh");
James Feistb943aae2019-07-11 16:33:56 -07001043 }
1044 else
1045 {
Ed Tanous62598e32023-07-17 17:06:25 -07001046 BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
Ed Tanous9e9b6042024-03-06 14:18:28 -08001047 messages::propertyValueNotInList(response->res, name,
Ed Tanousace85d62021-10-26 12:45:59 -07001048 "SetPointOffset");
James Feistb943aae2019-07-11 16:33:56 -07001049 return CreatePIDRet::fail;
1050 }
1051 }
1052
James Feist5f2caae2018-12-12 14:08:25 -08001053 // doubles
1054 for (const auto& pairs : doubles)
1055 {
1056 if (!pairs.second)
James Feist83ff9ab2018-08-31 10:18:24 -07001057 {
James Feist5f2caae2018-12-12 14:08:25 -08001058 continue;
James Feist83ff9ab2018-08-31 10:18:24 -07001059 }
Ed Tanous62598e32023-07-17 17:06:25 -07001060 BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -08001061 output.emplace_back(pairs.first, *pairs.second);
James Feist83ff9ab2018-08-31 10:18:24 -07001062 }
1063 }
James Feist5f2caae2018-12-12 14:08:25 -08001064
James Feist83ff9ab2018-08-31 10:18:24 -07001065 else if (type == "FanZones")
1066 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001067 output.emplace_back("Type", "Pid.Zone");
James Feist83ff9ab2018-08-31 10:18:24 -07001068
Ed Tanous9e9b6042024-03-06 14:18:28 -08001069 std::optional<std::string> chassisId;
James Feist5f2caae2018-12-12 14:08:25 -08001070 std::optional<double> failSafePercent;
James Feistd3ec07f2019-02-25 14:51:15 -08001071 std::optional<double> minThermalOutput;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001072 if (!redfish::json_util::readJson(
1073 jsonValue, response->res, "Chassis/@odata.id", chassisId,
1074 "FailSafePercent", failSafePercent, "MinThermalOutput",
1075 minThermalOutput))
James Feist83ff9ab2018-08-31 10:18:24 -07001076 {
James Feist5f2caae2018-12-12 14:08:25 -08001077 return CreatePIDRet::fail;
1078 }
James Feist83ff9ab2018-08-31 10:18:24 -07001079
Ed Tanous9e9b6042024-03-06 14:18:28 -08001080 if (chassisId)
James Feist5f2caae2018-12-12 14:08:25 -08001081 {
AppaRao Puli717794d2019-10-18 22:54:53 +05301082 // /redfish/v1/chassis/chassis_name/
Ed Tanous9e9b6042024-03-06 14:18:28 -08001083 if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
James Feist5f2caae2018-12-12 14:08:25 -08001084 {
Ed Tanous9e9b6042024-03-06 14:18:28 -08001085 BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
Ed Tanousace85d62021-10-26 12:45:59 -07001086 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001087 response->res,
Ed Tanous9e9b6042024-03-06 14:18:28 -08001088 boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
James Feist5f2caae2018-12-12 14:08:25 -08001089 return CreatePIDRet::fail;
1090 }
1091 }
James Feistd3ec07f2019-02-25 14:51:15 -08001092 if (minThermalOutput)
James Feist5f2caae2018-12-12 14:08:25 -08001093 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001094 output.emplace_back("MinThermalOutput", *minThermalOutput);
James Feist5f2caae2018-12-12 14:08:25 -08001095 }
1096 if (failSafePercent)
1097 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001098 output.emplace_back("FailSafePercent", *failSafePercent);
James Feist5f2caae2018-12-12 14:08:25 -08001099 }
1100 }
1101 else if (type == "StepwiseControllers")
1102 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001103 output.emplace_back("Type", "Stepwise");
James Feist5f2caae2018-12-12 14:08:25 -08001104
Ed Tanous9e9b6042024-03-06 14:18:28 -08001105 std::optional<std::vector<nlohmann::json::object_t>> zones;
1106 std::optional<std::vector<nlohmann::json::object_t>> steps;
James Feist5f2caae2018-12-12 14:08:25 -08001107 std::optional<std::vector<std::string>> inputs;
1108 std::optional<double> positiveHysteresis;
1109 std::optional<double> negativeHysteresis;
James Feistc33a90e2019-03-01 10:17:44 -08001110 std::optional<std::string> direction; // upper clipping curve vs lower
James Feist5f2caae2018-12-12 14:08:25 -08001111 if (!redfish::json_util::readJson(
Ed Tanous9e9b6042024-03-06 14:18:28 -08001112 jsonValue, response->res, "Zones", zones, "Steps", steps,
James Feistb6baeaa2019-02-21 10:41:40 -08001113 "Inputs", inputs, "PositiveHysteresis", positiveHysteresis,
James Feistc33a90e2019-03-01 10:17:44 -08001114 "NegativeHysteresis", negativeHysteresis, "Direction",
1115 direction))
James Feist5f2caae2018-12-12 14:08:25 -08001116 {
James Feist5f2caae2018-12-12 14:08:25 -08001117 return CreatePIDRet::fail;
1118 }
1119
1120 if (zones)
1121 {
James Feistb6baeaa2019-02-21 10:41:40 -08001122 std::vector<std::string> zonesStrs;
1123 if (!getZonesFromJsonReq(response, *zones, zonesStrs))
James Feist5f2caae2018-12-12 14:08:25 -08001124 {
Ed Tanous62598e32023-07-17 17:06:25 -07001125 BMCWEB_LOG_ERROR("Illegal Zones");
James Feist5f2caae2018-12-12 14:08:25 -08001126 return CreatePIDRet::fail;
1127 }
James Feistb6baeaa2019-02-21 10:41:40 -08001128 if (chassis.empty() &&
Ed Tanouse662eae2022-01-25 10:39:19 -08001129 findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
James Feistb6baeaa2019-02-21 10:41:40 -08001130 {
Ed Tanous62598e32023-07-17 17:06:25 -07001131 BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
Ed Tanousace85d62021-10-26 12:45:59 -07001132 messages::invalidObject(
Ed Tanousef4c65b2023-04-24 15:28:50 -07001133 response->res,
1134 boost::urls::format("/redfish/v1/Chassis/{}", chassis));
James Feistb6baeaa2019-02-21 10:41:40 -08001135 return CreatePIDRet::fail;
1136 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001137 output.emplace_back("Zones", std::move(zonesStrs));
James Feist5f2caae2018-12-12 14:08:25 -08001138 }
1139 if (steps)
1140 {
1141 std::vector<double> readings;
1142 std::vector<double> outputs;
1143 for (auto& step : *steps)
1144 {
Ed Tanous543f4402022-01-06 13:12:53 -08001145 double target = 0.0;
1146 double out = 0.0;
James Feist5f2caae2018-12-12 14:08:25 -08001147
Ed Tanous9e9b6042024-03-06 14:18:28 -08001148 if (!redfish::json_util::readJsonObject(
1149 step, response->res, "Target", target, "Output", out))
James Feist5f2caae2018-12-12 14:08:25 -08001150 {
James Feist5f2caae2018-12-12 14:08:25 -08001151 return CreatePIDRet::fail;
1152 }
1153 readings.emplace_back(target);
Ed Tanous23a21a12020-07-25 04:45:05 +00001154 outputs.emplace_back(out);
James Feist5f2caae2018-12-12 14:08:25 -08001155 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001156 output.emplace_back("Reading", std::move(readings));
1157 output.emplace_back("Output", std::move(outputs));
James Feist5f2caae2018-12-12 14:08:25 -08001158 }
1159 if (inputs)
1160 {
1161 for (std::string& value : *inputs)
1162 {
Ed Tanousa170f272022-06-30 21:53:27 -07001163 std::replace(value.begin(), value.end(), '_', ' ');
James Feist5f2caae2018-12-12 14:08:25 -08001164 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001165 output.emplace_back("Inputs", std::move(*inputs));
James Feist5f2caae2018-12-12 14:08:25 -08001166 }
1167 if (negativeHysteresis)
1168 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001169 output.emplace_back("NegativeHysteresis", *negativeHysteresis);
James Feist5f2caae2018-12-12 14:08:25 -08001170 }
1171 if (positiveHysteresis)
1172 {
Ed Tanousb9d36b42022-02-26 21:42:46 -08001173 output.emplace_back("PositiveHysteresis", *positiveHysteresis);
James Feist83ff9ab2018-08-31 10:18:24 -07001174 }
James Feistc33a90e2019-03-01 10:17:44 -08001175 if (direction)
1176 {
1177 constexpr const std::array<const char*, 2> allowedDirections = {
1178 "Ceiling", "Floor"};
Ed Tanous3544d2a2023-08-06 18:12:20 -07001179 if (std::ranges::find(allowedDirections, *direction) ==
1180 allowedDirections.end())
James Feistc33a90e2019-03-01 10:17:44 -08001181 {
1182 messages::propertyValueTypeError(response->res, "Direction",
1183 *direction);
1184 return CreatePIDRet::fail;
1185 }
Ed Tanousb9d36b42022-02-26 21:42:46 -08001186 output.emplace_back("Class", *direction);
James Feistc33a90e2019-03-01 10:17:44 -08001187 }
James Feist83ff9ab2018-08-31 10:18:24 -07001188 }
1189 else
1190 {
Ed Tanous62598e32023-07-17 17:06:25 -07001191 BMCWEB_LOG_ERROR("Illegal Type {}", type);
Jason M. Bills35a62c72018-10-09 12:45:45 -07001192 messages::propertyUnknown(response->res, type);
James Feist83ff9ab2018-08-31 10:18:24 -07001193 return CreatePIDRet::fail;
1194 }
1195 return CreatePIDRet::patch;
1196}
James Feist73df0db2019-03-25 15:29:35 -07001197struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
1198{
Ed Tanous6936afe2022-09-08 15:10:39 -07001199 struct CompletionValues
1200 {
1201 std::vector<std::string> supportedProfiles;
1202 std::string currentProfile;
1203 dbus::utility::MapperGetSubTreeResponse subtree;
1204 };
James Feist73df0db2019-03-25 15:29:35 -07001205
Ed Tanous4e23a442022-06-06 09:57:26 -07001206 explicit GetPIDValues(
1207 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +00001208 asyncResp(asyncRespIn)
James Feist73df0db2019-03-25 15:29:35 -07001209
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001210 {}
James Feist73df0db2019-03-25 15:29:35 -07001211
1212 void run()
1213 {
1214 std::shared_ptr<GetPIDValues> self = shared_from_this();
1215
1216 // get all configurations
George Liue99073f2022-12-09 11:06:16 +08001217 constexpr std::array<std::string_view, 4> interfaces = {
1218 pidConfigurationIface, pidZoneConfigurationIface,
1219 objectManagerIface, stepwiseConfigurationIface};
1220 dbus::utility::getSubTree(
1221 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001222 [self](
George Liue99073f2022-12-09 11:06:16 +08001223 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001224 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001225 if (ec)
1226 {
1227 BMCWEB_LOG_ERROR("{}", ec);
1228 messages::internalError(self->asyncResp->res);
1229 return;
1230 }
1231 self->complete.subtree = subtreeLocal;
1232 });
James Feist73df0db2019-03-25 15:29:35 -07001233
1234 // at the same time get the selected profile
George Liue99073f2022-12-09 11:06:16 +08001235 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1236 thermalModeIface};
1237 dbus::utility::getSubTree(
1238 "/", 0, thermalModeIfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001239 [self](
George Liue99073f2022-12-09 11:06:16 +08001240 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001241 const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001242 if (ec || subtreeLocal.empty())
James Feist73df0db2019-03-25 15:29:35 -07001243 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001244 return;
1245 }
1246 if (subtreeLocal[0].second.size() != 1)
1247 {
1248 // invalid mapper response, should never happen
1249 BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
James Feist73df0db2019-03-25 15:29:35 -07001250 messages::internalError(self->asyncResp->res);
1251 return;
1252 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001253
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001254 const std::string& path = subtreeLocal[0].first;
1255 const std::string& owner = subtreeLocal[0].second[0].first;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001256
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001257 sdbusplus::asio::getAllProperties(
1258 *crow::connections::systemBus, owner, path,
1259 thermalModeIface,
1260 [path, owner,
1261 self](const boost::system::error_code& ec2,
1262 const dbus::utility::DBusPropertiesMap& resp) {
1263 if (ec2)
1264 {
1265 BMCWEB_LOG_ERROR(
1266 "GetPIDValues: Can't get thermalModeIface {}",
1267 path);
1268 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* current = nullptr;
1273 const std::vector<std::string>* supported = nullptr;
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001274
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001275 const bool success = sdbusplus::unpackPropertiesNoThrow(
1276 dbus_utils::UnpackErrorPrinter(), resp, "Current",
1277 current, "Supported", supported);
1278
1279 if (!success)
1280 {
1281 messages::internalError(self->asyncResp->res);
1282 return;
1283 }
1284
1285 if (current == nullptr || supported == nullptr)
1286 {
1287 BMCWEB_LOG_ERROR(
1288 "GetPIDValues: thermal mode iface invalid {}",
1289 path);
1290 messages::internalError(self->asyncResp->res);
1291 return;
1292 }
1293 self->complete.currentProfile = *current;
1294 self->complete.supportedProfiles = *supported;
1295 });
George Liue99073f2022-12-09 11:06:16 +08001296 });
James Feist73df0db2019-03-25 15:29:35 -07001297 }
1298
Ed Tanous6936afe2022-09-08 15:10:39 -07001299 static void
1300 processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1301 const CompletionValues& completion)
James Feist73df0db2019-03-25 15:29:35 -07001302 {
1303 if (asyncResp->res.result() != boost::beast::http::status::ok)
1304 {
1305 return;
1306 }
1307 // create map of <connection, path to objMgr>>
Ed Tanous6936afe2022-09-08 15:10:39 -07001308 boost::container::flat_map<
1309 std::string, std::string, std::less<>,
1310 std::vector<std::pair<std::string, std::string>>>
1311 objectMgrPaths;
1312 boost::container::flat_set<std::string, std::less<>,
1313 std::vector<std::string>>
1314 calledConnections;
1315 for (const auto& pathGroup : completion.subtree)
James Feist73df0db2019-03-25 15:29:35 -07001316 {
1317 for (const auto& connectionGroup : pathGroup.second)
1318 {
1319 auto findConnection =
1320 calledConnections.find(connectionGroup.first);
1321 if (findConnection != calledConnections.end())
1322 {
1323 break;
1324 }
1325 for (const std::string& interface : connectionGroup.second)
1326 {
1327 if (interface == objectManagerIface)
1328 {
1329 objectMgrPaths[connectionGroup.first] = pathGroup.first;
1330 }
1331 // this list is alphabetical, so we
1332 // should have found the objMgr by now
1333 if (interface == pidConfigurationIface ||
1334 interface == pidZoneConfigurationIface ||
1335 interface == stepwiseConfigurationIface)
1336 {
1337 auto findObjMgr =
1338 objectMgrPaths.find(connectionGroup.first);
1339 if (findObjMgr == objectMgrPaths.end())
1340 {
Ed Tanous62598e32023-07-17 17:06:25 -07001341 BMCWEB_LOG_DEBUG("{}Has no Object Manager",
1342 connectionGroup.first);
James Feist73df0db2019-03-25 15:29:35 -07001343 continue;
1344 }
1345
1346 calledConnections.insert(connectionGroup.first);
1347
1348 asyncPopulatePid(findObjMgr->first, findObjMgr->second,
Ed Tanous6936afe2022-09-08 15:10:39 -07001349 completion.currentProfile,
1350 completion.supportedProfiles,
James Feist73df0db2019-03-25 15:29:35 -07001351 asyncResp);
1352 break;
1353 }
1354 }
1355 }
1356 }
1357 }
1358
Ed Tanous6936afe2022-09-08 15:10:39 -07001359 ~GetPIDValues()
1360 {
1361 boost::asio::post(crow::connections::systemBus->get_io_context(),
1362 std::bind_front(&processingComplete, asyncResp,
1363 std::move(complete)));
1364 }
1365
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001366 GetPIDValues(const GetPIDValues&) = delete;
1367 GetPIDValues(GetPIDValues&&) = delete;
1368 GetPIDValues& operator=(const GetPIDValues&) = delete;
1369 GetPIDValues& operator=(GetPIDValues&&) = delete;
1370
zhanghch058d1b46d2021-04-01 11:18:24 +08001371 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous6936afe2022-09-08 15:10:39 -07001372 CompletionValues complete;
James Feist73df0db2019-03-25 15:29:35 -07001373};
1374
1375struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
1376{
Ed Tanous9e9b6042024-03-06 14:18:28 -08001377 SetPIDValues(
1378 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
1379 std::vector<
1380 std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
1381 configurationsIn,
1382 std::optional<std::string>& profileIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001383 asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
Ed Tanous9e9b6042024-03-06 14:18:28 -08001384 profile(std::move(profileIn))
1385 {}
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001386
1387 SetPIDValues(const SetPIDValues&) = delete;
1388 SetPIDValues(SetPIDValues&&) = delete;
1389 SetPIDValues& operator=(const SetPIDValues&) = delete;
1390 SetPIDValues& operator=(SetPIDValues&&) = delete;
1391
James Feist73df0db2019-03-25 15:29:35 -07001392 void run()
1393 {
1394 if (asyncResp->res.result() != boost::beast::http::status::ok)
1395 {
1396 return;
1397 }
1398
1399 std::shared_ptr<SetPIDValues> self = shared_from_this();
1400
1401 // todo(james): might make sense to do a mapper call here if this
1402 // interface gets more traction
George Liu5eb468d2023-06-20 17:03:24 +08001403 sdbusplus::message::object_path objPath(
1404 "/xyz/openbmc_project/inventory");
1405 dbus::utility::getManagedObjects(
1406 "xyz.openbmc_project.EntityManager", objPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001407 [self](const boost::system::error_code& ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001408 const dbus::utility::ManagedObjectType& mObj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001409 if (ec)
James Feiste69d9de2020-02-07 12:23:27 -08001410 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001411 BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
1412 messages::internalError(self->asyncResp->res);
1413 return;
1414 }
1415 const std::array<const char*, 3> configurations = {
1416 pidConfigurationIface, pidZoneConfigurationIface,
1417 stepwiseConfigurationIface};
1418
1419 for (const auto& [path, object] : mObj)
1420 {
1421 for (const auto& [interface, _] : object)
James Feiste69d9de2020-02-07 12:23:27 -08001422 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001423 if (std::ranges::find(configurations, interface) !=
1424 configurations.end())
1425 {
1426 self->objectCount++;
1427 break;
1428 }
James Feiste69d9de2020-02-07 12:23:27 -08001429 }
James Feiste69d9de2020-02-07 12:23:27 -08001430 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001431 self->managedObj = mObj;
1432 });
James Feist73df0db2019-03-25 15:29:35 -07001433
1434 // at the same time get the profile information
George Liue99073f2022-12-09 11:06:16 +08001435 constexpr std::array<std::string_view, 1> thermalModeIfaces = {
1436 thermalModeIface};
1437 dbus::utility::getSubTree(
1438 "/", 0, thermalModeIfaces,
1439 [self](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001440 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001441 if (ec || subtree.empty())
James Feist73df0db2019-03-25 15:29:35 -07001442 {
James Feist73df0db2019-03-25 15:29:35 -07001443 return;
1444 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001445 if (subtree[0].second.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001446 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001447 // invalid mapper response, should never happen
1448 BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001449 messages::internalError(self->asyncResp->res);
1450 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001451 }
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02001452
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001453 const std::string& path = subtree[0].first;
1454 const std::string& owner = subtree[0].second[0].first;
1455 sdbusplus::asio::getAllProperties(
1456 *crow::connections::systemBus, owner, path,
1457 thermalModeIface,
1458 [self, path,
1459 owner](const boost::system::error_code& ec2,
1460 const dbus::utility::DBusPropertiesMap& r) {
1461 if (ec2)
1462 {
1463 BMCWEB_LOG_ERROR(
1464 "SetPIDValues: Can't get thermalModeIface {}",
1465 path);
1466 messages::internalError(self->asyncResp->res);
1467 return;
1468 }
1469 const std::string* current = nullptr;
1470 const std::vector<std::string>* supported = nullptr;
1471
1472 const bool success = sdbusplus::unpackPropertiesNoThrow(
1473 dbus_utils::UnpackErrorPrinter(), r, "Current",
1474 current, "Supported", supported);
1475
1476 if (!success)
1477 {
1478 messages::internalError(self->asyncResp->res);
1479 return;
1480 }
1481
1482 if (current == nullptr || supported == nullptr)
1483 {
1484 BMCWEB_LOG_ERROR(
1485 "SetPIDValues: thermal mode iface invalid {}",
1486 path);
1487 messages::internalError(self->asyncResp->res);
1488 return;
1489 }
1490 self->currentProfile = *current;
1491 self->supportedProfiles = *supported;
1492 self->profileConnection = owner;
1493 self->profilePath = path;
1494 });
George Liue99073f2022-12-09 11:06:16 +08001495 });
James Feist73df0db2019-03-25 15:29:35 -07001496 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001497 void pidSetDone()
James Feist73df0db2019-03-25 15:29:35 -07001498 {
1499 if (asyncResp->res.result() != boost::beast::http::status::ok)
1500 {
1501 return;
1502 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001503 std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
James Feist73df0db2019-03-25 15:29:35 -07001504 if (profile)
1505 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07001506 if (std::ranges::find(supportedProfiles, *profile) ==
1507 supportedProfiles.end())
James Feist73df0db2019-03-25 15:29:35 -07001508 {
1509 messages::actionParameterUnknown(response->res, "Profile",
1510 *profile);
1511 return;
1512 }
1513 currentProfile = *profile;
George Liu9ae226f2023-06-21 17:56:46 +08001514 sdbusplus::asio::setProperty(
1515 *crow::connections::systemBus, profileConnection, profilePath,
1516 thermalModeIface, "Current", *profile,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001517 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001518 if (ec)
1519 {
1520 BMCWEB_LOG_ERROR("Error patching profile{}", ec);
1521 messages::internalError(response->res);
1522 }
1523 });
James Feist73df0db2019-03-25 15:29:35 -07001524 }
1525
1526 for (auto& containerPair : configuration)
1527 {
1528 auto& container = containerPair.second;
1529 if (!container)
1530 {
1531 continue;
1532 }
James Feist6ee7f772020-02-06 16:25:27 -08001533
Ed Tanous02cad962022-06-30 16:50:15 -07001534 const std::string& type = containerPair.first;
James Feist73df0db2019-03-25 15:29:35 -07001535
Ed Tanous9e9b6042024-03-06 14:18:28 -08001536 for (auto& [name, value] : *container)
James Feist73df0db2019-03-25 15:29:35 -07001537 {
Potin Laicddbf3d2023-02-14 14:28:58 +08001538 std::string dbusObjName = name;
1539 std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
Ed Tanous62598e32023-07-17 17:06:25 -07001540 BMCWEB_LOG_DEBUG("looking for {}", name);
James Feist6ee7f772020-02-06 16:25:27 -08001541
Ed Tanous3544d2a2023-08-06 18:12:20 -07001542 auto pathItr = std::ranges::find_if(
1543 managedObj, [&dbusObjName](const auto& obj) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001544 return obj.first.filename() == dbusObjName;
1545 });
Ed Tanousb9d36b42022-02-26 21:42:46 -08001546 dbus::utility::DBusPropertiesMap output;
James Feist73df0db2019-03-25 15:29:35 -07001547
1548 output.reserve(16); // The pid interface length
1549
1550 // determines if we're patching entity-manager or
1551 // creating a new object
1552 bool createNewObject = (pathItr == managedObj.end());
Ed Tanous62598e32023-07-17 17:06:25 -07001553 BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
James Feist6ee7f772020-02-06 16:25:27 -08001554
James Feist73df0db2019-03-25 15:29:35 -07001555 std::string iface;
Ed Tanousea2b6702022-03-07 16:48:38 -08001556 if (!createNewObject)
James Feist73df0db2019-03-25 15:29:35 -07001557 {
Potin Lai8be2b5b2022-11-22 13:27:16 +08001558 bool findInterface = false;
Ed Tanousea2b6702022-03-07 16:48:38 -08001559 for (const auto& interface : pathItr->second)
James Feist73df0db2019-03-25 15:29:35 -07001560 {
Ed Tanousea2b6702022-03-07 16:48:38 -08001561 if (interface.first == pidConfigurationIface)
1562 {
1563 if (type == "PidControllers" ||
1564 type == "FanControllers")
1565 {
1566 iface = pidConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001567 findInterface = true;
1568 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001569 }
1570 }
1571 else if (interface.first == pidZoneConfigurationIface)
1572 {
1573 if (type == "FanZones")
1574 {
PavanKumarIntelda393502024-03-15 05:47:02 +00001575 iface = pidZoneConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001576 findInterface = true;
1577 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001578 }
1579 }
1580 else if (interface.first == stepwiseConfigurationIface)
1581 {
1582 if (type == "StepwiseControllers")
1583 {
1584 iface = stepwiseConfigurationIface;
Potin Lai8be2b5b2022-11-22 13:27:16 +08001585 findInterface = true;
1586 break;
Ed Tanousea2b6702022-03-07 16:48:38 -08001587 }
1588 }
James Feist73df0db2019-03-25 15:29:35 -07001589 }
Potin Lai8be2b5b2022-11-22 13:27:16 +08001590
1591 // create new object if interface not found
1592 if (!findInterface)
1593 {
1594 createNewObject = true;
1595 }
James Feist73df0db2019-03-25 15:29:35 -07001596 }
James Feist6ee7f772020-02-06 16:25:27 -08001597
Ed Tanous9e9b6042024-03-06 14:18:28 -08001598 if (createNewObject && value == nullptr)
James Feist6ee7f772020-02-06 16:25:27 -08001599 {
Gunnar Mills4e0453b2020-07-08 14:00:30 -05001600 // can't delete a non-existent object
Ed Tanous9e9b6042024-03-06 14:18:28 -08001601 messages::propertyValueNotInList(response->res, value,
Ed Tanouse2616cc2022-06-27 12:45:55 -07001602 name);
James Feist6ee7f772020-02-06 16:25:27 -08001603 continue;
1604 }
1605
1606 std::string path;
1607 if (pathItr != managedObj.end())
1608 {
1609 path = pathItr->first.str;
1610 }
1611
Ed Tanous62598e32023-07-17 17:06:25 -07001612 BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
James Feiste69d9de2020-02-07 12:23:27 -08001613
1614 // arbitrary limit to avoid attacks
1615 constexpr const size_t controllerLimit = 500;
James Feist14b0b8d2020-02-12 11:52:07 -08001616 if (createNewObject && objectCount >= controllerLimit)
James Feiste69d9de2020-02-07 12:23:27 -08001617 {
1618 messages::resourceExhaustion(response->res, type);
1619 continue;
1620 }
Ed Tanousa170f272022-06-30 21:53:27 -07001621 std::string escaped = name;
1622 std::replace(escaped.begin(), escaped.end(), '_', ' ');
1623 output.emplace_back("Name", escaped);
James Feist73df0db2019-03-25 15:29:35 -07001624
1625 std::string chassis;
1626 CreatePIDRet ret = createPidInterface(
Ed Tanous9e9b6042024-03-06 14:18:28 -08001627 response, type, name, value, path, managedObj,
1628 createNewObject, output, chassis, currentProfile);
James Feist73df0db2019-03-25 15:29:35 -07001629 if (ret == CreatePIDRet::fail)
1630 {
1631 return;
1632 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001633 if (ret == CreatePIDRet::del)
James Feist73df0db2019-03-25 15:29:35 -07001634 {
1635 continue;
1636 }
1637
1638 if (!createNewObject)
1639 {
1640 for (const auto& property : output)
1641 {
Potin Lai7a696972023-11-09 12:18:20 +08001642 crow::connections::systemBus->async_method_call(
James Feist73df0db2019-03-25 15:29:35 -07001643 [response,
1644 propertyName{std::string(property.first)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001645 const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001646 if (ec)
1647 {
1648 BMCWEB_LOG_ERROR("Error patching {}: {}",
1649 propertyName, ec);
1650 messages::internalError(response->res);
1651 return;
1652 }
1653 messages::success(response->res);
1654 },
Potin Lai7a696972023-11-09 12:18:20 +08001655 "xyz.openbmc_project.EntityManager", path,
1656 "org.freedesktop.DBus.Properties", "Set", iface,
1657 property.first, property.second);
James Feist73df0db2019-03-25 15:29:35 -07001658 }
1659 }
1660 else
1661 {
1662 if (chassis.empty())
1663 {
Ed Tanous62598e32023-07-17 17:06:25 -07001664 BMCWEB_LOG_ERROR("Failed to get chassis from config");
Ed Tanousace85d62021-10-26 12:45:59 -07001665 messages::internalError(response->res);
James Feist73df0db2019-03-25 15:29:35 -07001666 return;
1667 }
1668
1669 bool foundChassis = false;
1670 for (const auto& obj : managedObj)
1671 {
Ed Tanous91f75ca2024-06-10 13:56:43 -07001672 if (obj.first.filename() == chassis)
James Feist73df0db2019-03-25 15:29:35 -07001673 {
1674 chassis = obj.first.str;
1675 foundChassis = true;
1676 break;
1677 }
1678 }
1679 if (!foundChassis)
1680 {
Ed Tanous62598e32023-07-17 17:06:25 -07001681 BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
James Feist73df0db2019-03-25 15:29:35 -07001682 messages::resourceMissingAtURI(
Ed Tanousace85d62021-10-26 12:45:59 -07001683 response->res,
Ed Tanousef4c65b2023-04-24 15:28:50 -07001684 boost::urls::format("/redfish/v1/Chassis/{}",
1685 chassis));
James Feist73df0db2019-03-25 15:29:35 -07001686 return;
1687 }
1688
1689 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001690 [response](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001691 if (ec)
1692 {
1693 BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
1694 ec);
1695 messages::internalError(response->res);
1696 return;
1697 }
1698 messages::success(response->res);
1699 },
James Feist73df0db2019-03-25 15:29:35 -07001700 "xyz.openbmc_project.EntityManager", chassis,
1701 "xyz.openbmc_project.AddObject", "AddObject", output);
1702 }
1703 }
1704 }
1705 }
Ed Tanous24b2fe82022-01-06 12:45:54 -08001706
1707 ~SetPIDValues()
1708 {
1709 try
1710 {
1711 pidSetDone();
1712 }
1713 catch (...)
1714 {
Ed Tanous62598e32023-07-17 17:06:25 -07001715 BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -08001716 }
1717 }
1718
zhanghch058d1b46d2021-04-01 11:18:24 +08001719 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous9e9b6042024-03-06 14:18:28 -08001720 std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
James Feist73df0db2019-03-25 15:29:35 -07001721 configuration;
1722 std::optional<std::string> profile;
1723 dbus::utility::ManagedObjectType managedObj;
1724 std::vector<std::string> supportedProfiles;
1725 std::string currentProfile;
1726 std::string profileConnection;
1727 std::string profilePath;
James Feist14b0b8d2020-02-12 11:52:07 -08001728 size_t objectCount = 0;
James Feist73df0db2019-03-25 15:29:35 -07001729};
James Feist83ff9ab2018-08-31 10:18:24 -07001730
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001731/**
1732 * @brief Retrieves BMC manager location data over DBus
1733 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001734 * @param[in] asyncResp Shared pointer for completing asynchronous calls
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001735 * @param[in] connectionName - service name
1736 * @param[in] path - object path
1737 * @return none
1738 */
Ed Tanousac106bf2023-06-07 09:24:59 -07001739inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001740 const std::string& connectionName,
1741 const std::string& path)
1742{
Ed Tanous62598e32023-07-17 17:06:25 -07001743 BMCWEB_LOG_DEBUG("Get BMC manager Location data.");
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001744
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001745 sdbusplus::asio::getProperty<std::string>(
1746 *crow::connections::systemBus, connectionName, path,
1747 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanousac106bf2023-06-07 09:24:59 -07001748 [asyncResp](const boost::system::error_code& ec,
1749 const std::string& property) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001750 if (ec)
1751 {
1752 BMCWEB_LOG_DEBUG("DBUS response error for "
1753 "Location");
1754 messages::internalError(asyncResp->res);
1755 return;
1756 }
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001757
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001758 asyncResp->res
1759 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
1760 property;
1761 });
SunnySrivastava1984071d8fd2020-10-28 02:20:30 -05001762}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001763// avoid name collision systems.hpp
1764inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001765 managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001766{
Ed Tanous62598e32023-07-17 17:06:25 -07001767 BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time");
Ed Tanous52cc1122020-07-18 13:51:21 -07001768
Jonathan Doman1e1e5982021-06-11 09:36:17 -07001769 sdbusplus::asio::getProperty<uint64_t>(
1770 *crow::connections::systemBus, "xyz.openbmc_project.State.BMC",
1771 "/xyz/openbmc_project/state/bmc0", "xyz.openbmc_project.State.BMC",
1772 "LastRebootTime",
Ed Tanousac106bf2023-06-07 09:24:59 -07001773 [asyncResp](const boost::system::error_code& ec,
1774 const uint64_t lastResetTime) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001775 if (ec)
1776 {
1777 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1778 return;
1779 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001780
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001781 // LastRebootTime is epoch time, in milliseconds
1782 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19
1783 uint64_t lastResetTimeStamp = lastResetTime / 1000;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001784
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001785 // Convert to ISO 8601 standard
1786 asyncResp->res.jsonValue["LastResetTime"] =
1787 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1788 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001789}
1790
1791/**
1792 * @brief Set the running firmware image
1793 *
Ed Tanousac106bf2023-06-07 09:24:59 -07001794 * @param[i,o] asyncResp - Async response object
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001795 * @param[i] runningFirmwareTarget - Image to make the running image
1796 *
1797 * @return void
1798 */
1799inline void
Ed Tanousac106bf2023-06-07 09:24:59 -07001800 setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001801 const std::string& runningFirmwareTarget)
1802{
1803 // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id>
1804 std::string::size_type idPos = runningFirmwareTarget.rfind('/');
1805 if (idPos == std::string::npos)
1806 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001807 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001808 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001809 BMCWEB_LOG_DEBUG("Can't parse firmware ID!");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001810 return;
1811 }
1812 idPos++;
1813 if (idPos >= runningFirmwareTarget.size())
1814 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001815 messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget,
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001816 "@odata.id");
Ed Tanous62598e32023-07-17 17:06:25 -07001817 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001818 return;
1819 }
1820 std::string firmwareId = runningFirmwareTarget.substr(idPos);
1821
1822 // Make sure the image is valid before setting priority
George Liu5eb468d2023-06-20 17:03:24 +08001823 sdbusplus::message::object_path objPath("/xyz/openbmc_project/software");
1824 dbus::utility::getManagedObjects(
1825 "xyz.openbmc_project.Software.BMC.Updater", objPath,
1826 [asyncResp, firmwareId, runningFirmwareTarget](
1827 const boost::system::error_code& ec,
1828 const dbus::utility::ManagedObjectType& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001829 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001830 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001831 BMCWEB_LOG_DEBUG("D-Bus response error getting objects.");
Ed Tanousac106bf2023-06-07 09:24:59 -07001832 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001833 return;
1834 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001835
1836 if (subtree.empty())
1837 {
1838 BMCWEB_LOG_DEBUG("Can't find image!");
1839 messages::internalError(asyncResp->res);
1840 return;
1841 }
1842
1843 bool foundImage = false;
1844 for (const auto& object : subtree)
1845 {
1846 const std::string& path =
1847 static_cast<const std::string&>(object.first);
1848 std::size_t idPos2 = path.rfind('/');
1849
1850 if (idPos2 == std::string::npos)
1851 {
1852 continue;
1853 }
1854
1855 idPos2++;
1856 if (idPos2 >= path.size())
1857 {
1858 continue;
1859 }
1860
1861 if (path.substr(idPos2) == firmwareId)
1862 {
1863 foundImage = true;
1864 break;
1865 }
1866 }
1867
1868 if (!foundImage)
1869 {
1870 messages::propertyValueNotInList(
1871 asyncResp->res, runningFirmwareTarget, "@odata.id");
1872 BMCWEB_LOG_DEBUG("Invalid firmware ID.");
1873 return;
1874 }
1875
1876 BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.",
1877 firmwareId);
1878
1879 // Only support Immediate
1880 // An addition could be a Redfish Setting like
1881 // ActiveSoftwareImageApplyTime and support OnReset
1882 sdbusplus::asio::setProperty(
1883 *crow::connections::systemBus,
1884 "xyz.openbmc_project.Software.BMC.Updater",
1885 "/xyz/openbmc_project/software/" + firmwareId,
1886 "xyz.openbmc_project.Software.RedundancyPriority", "Priority",
1887 static_cast<uint8_t>(0),
1888 [asyncResp](const boost::system::error_code& ec2) {
1889 if (ec2)
1890 {
1891 BMCWEB_LOG_DEBUG("D-Bus response error setting.");
1892 messages::internalError(asyncResp->res);
1893 return;
1894 }
1895 doBMCGracefulRestart(asyncResp);
1896 });
George Liu5eb468d2023-06-20 17:03:24 +08001897 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001898}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001899
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001900inline void afterSetDateTime(
1901 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1902 const boost::system::error_code& ec, const sdbusplus::message_t& msg)
Ed Tanousc51afd52024-03-07 10:13:14 -08001903{
1904 if (ec)
1905 {
1906 BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
1907 ec);
1908 const sd_bus_error* dbusError = msg.get_error();
1909 if (dbusError != nullptr)
1910 {
1911 std::string_view errorName(dbusError->name);
1912 if (errorName ==
1913 "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
1914 {
1915 BMCWEB_LOG_DEBUG("Setting conflict");
1916 messages::propertyValueConflict(
1917 asyncResp->res, "DateTime",
1918 "Managers/NetworkProtocol/NTPProcotolEnabled");
1919 return;
1920 }
1921 }
1922 messages::internalError(asyncResp->res);
1923 return;
1924 }
1925 asyncResp->res.result(boost::beast::http::status::no_content);
1926}
1927
1928inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1929 const std::string& datetime)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001930{
Ed Tanous62598e32023-07-17 17:06:25 -07001931 BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001932
Ed Tanousc2e32002023-01-07 22:05:08 -08001933 std::optional<redfish::time_utils::usSinceEpoch> us =
1934 redfish::time_utils::dateStringToEpoch(datetime);
1935 if (!us)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001936 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001937 messages::propertyValueFormatError(asyncResp->res, datetime,
1938 "DateTime");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001939 return;
1940 }
Ed Tanousc51afd52024-03-07 10:13:14 -08001941 // Set the absolute datetime
1942 bool relative = false;
1943 bool interactive = false;
1944 crow::connections::systemBus->async_method_call(
1945 [asyncResp](const boost::system::error_code& ec,
1946 const sdbusplus::message_t& msg) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001947 afterSetDateTime(asyncResp, ec, msg);
1948 },
Ed Tanousc51afd52024-03-07 10:13:14 -08001949 "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
1950 "org.freedesktop.timedate1", "SetTime", us->count(), relative,
1951 interactive);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001952}
1953
Ed Tanous75815e52022-10-05 17:21:13 -07001954inline void
1955 checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1956{
1957 sdbusplus::asio::getProperty<std::string>(
1958 *crow::connections::systemBus, "org.freedesktop.systemd1",
1959 "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target",
1960 "org.freedesktop.systemd1.Unit", "ActiveState",
1961 [asyncResp](const boost::system::error_code& ec,
1962 const std::string& val) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001963 if (!ec)
Ed Tanous75815e52022-10-05 17:21:13 -07001964 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001965 if (val == "active")
1966 {
1967 asyncResp->res.jsonValue["Status"]["Health"] =
1968 resource::Health::Critical;
1969 asyncResp->res.jsonValue["Status"]["State"] =
1970 resource::State::Quiesced;
1971 return;
1972 }
Ed Tanous75815e52022-10-05 17:21:13 -07001973 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001974 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
1975 asyncResp->res.jsonValue["Status"]["State"] =
1976 resource::State::Enabled;
1977 });
Ed Tanous75815e52022-10-05 17:21:13 -07001978}
1979
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001980inline void requestRoutesManager(App& app)
1981{
1982 std::string uuid = persistent_data::getConfig().systemUuid;
1983
Ed Tanous253f11b2024-05-16 09:38:31 -07001984 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001985 .privileges(redfish::privileges::getManager)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001986 .methods(
1987 boost::beast::http::verb::
1988 get)([&app,
1989 uuid](const crow::Request& req,
1990 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1991 const std::string& managerId) {
1992 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1993 {
1994 return;
1995 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001996
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001997 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1998 {
1999 messages::resourceNotFound(asyncResp->res, "Manager",
2000 managerId);
2001 return;
2002 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002003
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002004 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2005 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2006 asyncResp->res.jsonValue["@odata.type"] =
2007 "#Manager.v1_14_0.Manager";
2008 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME;
2009 asyncResp->res.jsonValue["Name"] = "OpenBmc Manager";
2010 asyncResp->res.jsonValue["Description"] =
2011 "Baseboard Management Controller";
2012 asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On;
Ed Tanous14766872022-03-15 10:44:42 -07002013
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002014 asyncResp->res.jsonValue["ManagerType"] = manager::ManagerType::BMC;
2015 asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid();
2016 asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid;
2017 asyncResp->res.jsonValue["Model"] =
2018 "OpenBmc"; // TODO(ed), get model
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002019
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002020 asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2021 boost::urls::format("/redfish/v1/Managers/{}/LogServices",
Ed Tanous253f11b2024-05-16 09:38:31 -07002022 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002023 asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] =
2024 boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
2025 BMCWEB_REDFISH_MANAGER_URI_NAME);
2026 asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] =
2027 boost::urls::format(
2028 "/redfish/v1/Managers/{}/EthernetInterfaces",
2029 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002030
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002031 if constexpr (BMCWEB_VM_NBDPROXY)
Ed Tanous75815e52022-10-05 17:21:13 -07002032 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002033 asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] =
2034 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia",
2035 BMCWEB_REDFISH_MANAGER_URI_NAME);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002036 }
2037
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002038 // default oem data
2039 nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
2040 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
2041 oem["@odata.id"] =
2042 boost::urls::format("/redfish/v1/Managers/{}#/Oem",
2043 BMCWEB_REDFISH_MANAGER_URI_NAME);
2044 oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
2045 oemOpenbmc["@odata.id"] =
2046 boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
2047 BMCWEB_REDFISH_MANAGER_URI_NAME);
2048
2049 nlohmann::json::object_t certificates;
2050 certificates["@odata.id"] = boost::urls::format(
2051 "/redfish/v1/Managers/{}/Truststore/Certificates",
2052 BMCWEB_REDFISH_MANAGER_URI_NAME);
2053 oemOpenbmc["Certificates"] = std::move(certificates);
2054
2055 // Manager.Reset (an action) can be many values, OpenBMC only
2056 // supports BMC reboot.
2057 nlohmann::json& managerReset =
2058 asyncResp->res.jsonValue["Actions"]["#Manager.Reset"];
2059 managerReset["target"] = boost::urls::format(
2060 "/redfish/v1/Managers/{}/Actions/Manager.Reset",
2061 BMCWEB_REDFISH_MANAGER_URI_NAME);
2062 managerReset["@Redfish.ActionInfo"] =
2063 boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo",
2064 BMCWEB_REDFISH_MANAGER_URI_NAME);
2065
2066 // ResetToDefaults (Factory Reset) has values like
2067 // PreserveNetworkAndUsers and PreserveNetwork that aren't supported
2068 // on OpenBMC
2069 nlohmann::json& resetToDefaults =
2070 asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"];
2071 resetToDefaults["target"] = boost::urls::format(
2072 "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults",
2073 BMCWEB_REDFISH_MANAGER_URI_NAME);
2074 resetToDefaults["ResetType@Redfish.AllowableValues"] =
2075 nlohmann::json::array_t({"ResetAll"});
2076
2077 std::pair<std::string, std::string> redfishDateTimeOffset =
2078 redfish::time_utils::getDateTimeOffsetNow();
2079
2080 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2081 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2082 redfishDateTimeOffset.second;
2083
2084 // TODO (Gunnar): Remove these one day since moved to ComputerSystem
2085 // Still used by OCP profiles
2086 // https://github.com/opencomputeproject/OCP-Profiles/issues/23
2087 // Fill in SerialConsole info
2088 asyncResp->res.jsonValue["SerialConsole"]["ServiceEnabled"] = true;
2089 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2090 15;
2091 asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] =
2092 nlohmann::json::array_t({"IPMI", "SSH"});
2093 if constexpr (BMCWEB_KVM)
Ed Tanous002d39b2022-05-31 08:59:27 -07002094 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002095 // Fill in GraphicalConsole info
2096 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] =
2097 true;
2098 asyncResp->res
2099 .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4;
2100 asyncResp->res
2101 .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
2102 nlohmann::json::array_t({"KVMIP"});
2103 }
2104 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2105 {
2106 asyncResp->res
2107 .jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
2108
2109 nlohmann::json::array_t managerForServers;
2110 nlohmann::json::object_t manager;
2111 manager["@odata.id"] = std::format(
2112 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
2113 managerForServers.emplace_back(std::move(manager));
2114
2115 asyncResp->res.jsonValue["Links"]["ManagerForServers"] =
2116 std::move(managerForServers);
Ed Tanous002d39b2022-05-31 08:59:27 -07002117 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002118
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002119 sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose,
2120 "FirmwareVersion", true);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002121
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002122 managerGetLastResetTime(asyncResp);
2123
2124 // ManagerDiagnosticData is added for all BMCs.
2125 nlohmann::json& managerDiagnosticData =
2126 asyncResp->res.jsonValue["ManagerDiagnosticData"];
2127 managerDiagnosticData["@odata.id"] = boost::urls::format(
2128 "/redfish/v1/Managers/{}/ManagerDiagnosticData",
2129 BMCWEB_REDFISH_MANAGER_URI_NAME);
2130
2131 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
Ed Tanous002d39b2022-05-31 08:59:27 -07002132 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002133 auto pids = std::make_shared<GetPIDValues>(asyncResp);
2134 pids->run();
2135 }
2136
2137 getMainChassisId(asyncResp, [](const std::string& chassisId,
2138 const std::shared_ptr<
2139 bmcweb::AsyncResp>& aRsp) {
2140 aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] =
2141 1;
2142 nlohmann::json::array_t managerForChassis;
2143 nlohmann::json::object_t managerObj;
2144 boost::urls::url chassiUrl =
2145 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
2146 managerObj["@odata.id"] = chassiUrl;
2147 managerForChassis.emplace_back(std::move(managerObj));
2148 aRsp->res.jsonValue["Links"]["ManagerForChassis"] =
2149 std::move(managerForChassis);
2150 aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] =
2151 chassiUrl;
2152 });
2153
2154 sdbusplus::asio::getProperty<double>(
2155 *crow::connections::systemBus, "org.freedesktop.systemd1",
2156 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
2157 "Progress",
2158 [asyncResp](const boost::system::error_code& ec, double val) {
2159 if (ec)
2160 {
2161 BMCWEB_LOG_ERROR("Error while getting progress");
2162 messages::internalError(asyncResp->res);
2163 return;
2164 }
2165 if (val < 1.0)
2166 {
2167 asyncResp->res.jsonValue["Status"]["Health"] =
2168 resource::Health::OK;
2169 asyncResp->res.jsonValue["Status"]["State"] =
2170 resource::State::Starting;
2171 return;
2172 }
2173 checkForQuiesced(asyncResp);
2174 });
2175
2176 constexpr std::array<std::string_view, 1> interfaces = {
2177 "xyz.openbmc_project.Inventory.Item.Bmc"};
2178 dbus::utility::getSubTree(
2179 "/xyz/openbmc_project/inventory", 0, interfaces,
2180 [asyncResp](
2181 const boost::system::error_code& ec,
2182 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2183 if (ec)
2184 {
2185 BMCWEB_LOG_DEBUG(
2186 "D-Bus response error on GetSubTree {}", ec);
2187 return;
2188 }
2189 if (subtree.empty())
2190 {
2191 BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!");
2192 return;
2193 }
2194 // Assume only 1 bmc D-Bus object
2195 // Throw an error if there is more than 1
2196 if (subtree.size() > 1)
2197 {
2198 BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!");
2199 messages::internalError(asyncResp->res);
2200 return;
2201 }
2202
2203 if (subtree[0].first.empty() ||
2204 subtree[0].second.size() != 1)
2205 {
2206 BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!");
2207 messages::internalError(asyncResp->res);
2208 return;
2209 }
2210
2211 const std::string& path = subtree[0].first;
2212 const std::string& connectionName =
2213 subtree[0].second[0].first;
2214
2215 for (const auto& interfaceName :
2216 subtree[0].second[0].second)
2217 {
2218 if (interfaceName ==
2219 "xyz.openbmc_project.Inventory.Decorator.Asset")
2220 {
2221 sdbusplus::asio::getAllProperties(
2222 *crow::connections::systemBus, connectionName,
2223 path,
2224 "xyz.openbmc_project.Inventory.Decorator.Asset",
2225 [asyncResp](
2226 const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08002227 const dbus::utility::DBusPropertiesMap&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002228 propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002229 if (ec2)
2230 {
2231 BMCWEB_LOG_DEBUG(
2232 "Can't get bmc asset!");
2233 return;
2234 }
2235
2236 const std::string* partNumber = nullptr;
2237 const std::string* serialNumber = nullptr;
2238 const std::string* manufacturer = nullptr;
2239 const std::string* model = nullptr;
2240 const std::string* sparePartNumber =
2241 nullptr;
2242
2243 const bool success =
2244 sdbusplus::unpackPropertiesNoThrow(
2245 dbus_utils::UnpackErrorPrinter(),
2246 propertiesList, "PartNumber",
2247 partNumber, "SerialNumber",
2248 serialNumber, "Manufacturer",
2249 manufacturer, "Model", model,
2250 "SparePartNumber", sparePartNumber);
2251
2252 if (!success)
2253 {
2254 messages::internalError(asyncResp->res);
2255 return;
2256 }
2257
2258 if (partNumber != nullptr)
2259 {
2260 asyncResp->res.jsonValue["PartNumber"] =
2261 *partNumber;
2262 }
2263
2264 if (serialNumber != nullptr)
2265 {
2266 asyncResp->res
2267 .jsonValue["SerialNumber"] =
2268 *serialNumber;
2269 }
2270
2271 if (manufacturer != nullptr)
2272 {
2273 asyncResp->res
2274 .jsonValue["Manufacturer"] =
2275 *manufacturer;
2276 }
2277
2278 if (model != nullptr)
2279 {
2280 asyncResp->res.jsonValue["Model"] =
2281 *model;
2282 }
2283
2284 if (sparePartNumber != nullptr)
2285 {
2286 asyncResp->res
2287 .jsonValue["SparePartNumber"] =
2288 *sparePartNumber;
2289 }
2290 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002291 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002292 else if (
2293 interfaceName ==
2294 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Krzysztof Grobelnyfac6e532022-08-04 12:42:45 +02002295 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002296 getLocation(asyncResp, connectionName, path);
Ed Tanous002d39b2022-05-31 08:59:27 -07002297 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002298 }
2299 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002300 });
2301
Ed Tanous253f11b2024-05-16 09:38:31 -07002302 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002303 .privileges(redfish::privileges::patchManager)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002304 .methods(boost::beast::http::verb::patch)(
2305 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002306 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2307 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002308 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2309 {
2310 return;
2311 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002312
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002313 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2314 {
2315 messages::resourceNotFound(asyncResp->res, "Manager",
2316 managerId);
2317 return;
2318 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002319
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002320 std::optional<std::string> activeSoftwareImageOdataId;
2321 std::optional<std::string> datetime;
2322 std::optional<nlohmann::json::object_t> pidControllers;
2323 std::optional<nlohmann::json::object_t> fanControllers;
2324 std::optional<nlohmann::json::object_t> fanZones;
2325 std::optional<nlohmann::json::object_t> stepwiseControllers;
2326 std::optional<std::string> profile;
Ed Tanous002d39b2022-05-31 08:59:27 -07002327
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002328 // clang-format off
Ed Tanous9e9b6042024-03-06 14:18:28 -08002329 if (!json_util::readJsonPatch(req, asyncResp->res,
2330 "DateTime", datetime,
2331 "Links/ActiveSoftwareImage/@odata.id", activeSoftwareImageOdataId,
2332 "Oem/OpenBmc/Fan/FanControllers", fanControllers,
2333 "Oem/OpenBmc/Fan/FanZones", fanZones,
2334 "Oem/OpenBmc/Fan/PidControllers", pidControllers,
2335 "Oem/OpenBmc/Fan/Profile", profile,
2336 "Oem/OpenBmc/Fan/StepwiseControllers", stepwiseControllers
2337 ))
Ed Tanous002d39b2022-05-31 08:59:27 -07002338 {
2339 return;
2340 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002341 // clang-format on
Ed Tanous002d39b2022-05-31 08:59:27 -07002342
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002343 if (pidControllers || fanControllers || fanZones ||
2344 stepwiseControllers || profile)
2345 {
2346 if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA)
2347 {
2348 std::vector<
2349 std::pair<std::string,
Ed Tanous25b54db2024-04-17 15:40:31 -07002350 std::optional<nlohmann::json::object_t>>>
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002351 configuration;
2352 if (pidControllers)
2353 {
2354 configuration.emplace_back(
2355 "PidControllers", std::move(pidControllers));
2356 }
2357 if (fanControllers)
2358 {
2359 configuration.emplace_back(
2360 "FanControllers", std::move(fanControllers));
2361 }
2362 if (fanZones)
2363 {
2364 configuration.emplace_back("FanZones",
2365 std::move(fanZones));
2366 }
2367 if (stepwiseControllers)
2368 {
2369 configuration.emplace_back(
2370 "StepwiseControllers",
2371 std::move(stepwiseControllers));
2372 }
2373 auto pid = std::make_shared<SetPIDValues>(
2374 asyncResp, std::move(configuration), profile);
2375 pid->run();
2376 }
2377 else
2378 {
2379 messages::propertyUnknown(asyncResp->res, "Oem");
2380 return;
2381 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002382 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002383
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002384 if (activeSoftwareImageOdataId)
2385 {
2386 setActiveFirmwareImage(asyncResp,
2387 *activeSoftwareImageOdataId);
2388 }
Ed Tanous9e9b6042024-03-06 14:18:28 -08002389
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002390 if (datetime)
2391 {
2392 setDateTime(asyncResp, *datetime);
2393 }
2394 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002395}
2396
2397inline void requestRoutesManagerCollection(App& app)
2398{
2399 BMCWEB_ROUTE(app, "/redfish/v1/Managers/")
Ed Tanoused398212021-06-09 17:05:54 -07002400 .privileges(redfish::privileges::getManagerCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002401 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002402 [&app](const crow::Request& req,
2403 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002404 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2405 {
2406 return;
2407 }
2408 // Collections don't include the static data added by SubRoute
2409 // because it has a duplicate entry for members
2410 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
2411 asyncResp->res.jsonValue["@odata.type"] =
2412 "#ManagerCollection.ManagerCollection";
2413 asyncResp->res.jsonValue["Name"] = "Manager Collection";
2414 asyncResp->res.jsonValue["Members@odata.count"] = 1;
2415 nlohmann::json::array_t members;
2416 nlohmann::json& bmc = members.emplace_back();
2417 bmc["@odata.id"] = boost::urls::format(
2418 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
2419 asyncResp->res.jsonValue["Members"] = std::move(members);
2420 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002421}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002422} // namespace redfish