blob: e9120f3d0cd409d9392d5ab1a5aa5d07061b2d14 [file] [log] [blame]
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include "node.hpp"
19
James Feist5b4aa862018-08-16 14:07:01 -070020#include <boost/algorithm/string/replace.hpp>
21#include <dbus_utility.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080022#include <variant>
James Feist5b4aa862018-08-16 14:07:01 -070023
Ed Tanous1abe55e2018-09-05 08:30:59 -070024namespace redfish
25{
Jennifer Leeed5befb2018-08-10 11:29:45 -070026
27/**
28 * ManagerActionsReset class supports handle POST method for Reset action.
29 * The class retrieves and sends data directly to dbus.
30 */
31class ManagerActionsReset : public Node
32{
33 public:
34 ManagerActionsReset(CrowApp& app) :
35 Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/")
36 {
37 entityPrivileges = {
38 {boost::beast::http::verb::get, {{"Login"}}},
39 {boost::beast::http::verb::head, {{"Login"}}},
40 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
41 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
42 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
43 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
44 }
45
46 private:
47 /**
Jennifer Leeed5befb2018-08-10 11:29:45 -070048 * Function handles POST method request.
49 * Analyzes POST body message before sends Reset request data to dbus.
50 * OpenBMC allows for ResetType is GracefulRestart only.
51 */
52 void doPost(crow::Response& res, const crow::Request& req,
53 const std::vector<std::string>& params) override
54 {
55 std::string resetType;
56
57 if (!json_util::readJson(req, res, "ResetType", resetType))
58 {
59 return;
60 }
61
62 if (resetType != "GracefulRestart")
63 {
64 res.result(boost::beast::http::status::bad_request);
65 messages::actionParameterNotSupported(res, resetType, "ResetType");
66 BMCWEB_LOG_ERROR << "Request incorrect action parameter: "
67 << resetType;
68 res.end();
69 return;
70 }
71 doBMCGracefulRestart(res, req, params);
72 }
73
74 /**
75 * Function transceives data with dbus directly.
76 * All BMC state properties will be retrieved before sending reset request.
77 */
78 void doBMCGracefulRestart(crow::Response& res, const crow::Request& req,
79 const std::vector<std::string>& params)
80 {
81 const char* processName = "xyz.openbmc_project.State.BMC";
82 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
83 const char* interfaceName = "xyz.openbmc_project.State.BMC";
84 const std::string& propertyValue =
85 "xyz.openbmc_project.State.BMC.Transition.Reboot";
86 const char* destProperty = "RequestedBMCTransition";
87
88 // Create the D-Bus variant for D-Bus call.
89 VariantType dbusPropertyValue(propertyValue);
90
91 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
92
93 crow::connections::systemBus->async_method_call(
94 [asyncResp](const boost::system::error_code ec) {
95 // Use "Set" method to set the property value.
96 if (ec)
97 {
98 BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec;
99 messages::internalError(asyncResp->res);
100 return;
101 }
102
103 messages::success(asyncResp->res);
104 },
105 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
106 interfaceName, destProperty, dbusPropertyValue);
107 }
108};
109
James Feist5b4aa862018-08-16 14:07:01 -0700110static constexpr const char* objectManagerIface =
111 "org.freedesktop.DBus.ObjectManager";
112static constexpr const char* pidConfigurationIface =
113 "xyz.openbmc_project.Configuration.Pid";
114static constexpr const char* pidZoneConfigurationIface =
115 "xyz.openbmc_project.Configuration.Pid.Zone";
James Feistb7a08d02018-12-11 14:55:37 -0800116static constexpr const char* stepwiseConfigurationIface =
117 "xyz.openbmc_project.Configuration.Stepwise";
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100118
James Feist5b4aa862018-08-16 14:07:01 -0700119static void asyncPopulatePid(const std::string& connection,
120 const std::string& path,
121 std::shared_ptr<AsyncResp> asyncResp)
122{
123
124 crow::connections::systemBus->async_method_call(
125 [asyncResp](const boost::system::error_code ec,
126 const dbus::utility::ManagedObjectType& managedObj) {
127 if (ec)
128 {
129 BMCWEB_LOG_ERROR << ec;
James Feist5b4aa862018-08-16 14:07:01 -0700130 asyncResp->res.jsonValue.clear();
Jason M. Billsf12894f2018-10-09 12:45:45 -0700131 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700132 return;
133 }
134 nlohmann::json& configRoot =
135 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
136 nlohmann::json& fans = configRoot["FanControllers"];
137 fans["@odata.type"] = "#OemManager.FanControllers";
138 fans["@odata.context"] =
139 "/redfish/v1/$metadata#OemManager.FanControllers";
140 fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
141 "Fan/FanControllers";
142
143 nlohmann::json& pids = configRoot["PidControllers"];
144 pids["@odata.type"] = "#OemManager.PidControllers";
145 pids["@odata.context"] =
146 "/redfish/v1/$metadata#OemManager.PidControllers";
147 pids["@odata.id"] =
148 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
149
James Feistb7a08d02018-12-11 14:55:37 -0800150 nlohmann::json& stepwise = configRoot["StepwiseControllers"];
151 stepwise["@odata.type"] = "#OemManager.StepwiseControllers";
152 stepwise["@odata.context"] =
153 "/redfish/v1/$metadata#OemManager.StepwiseControllers";
154 stepwise["@odata.id"] =
155 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers";
156
James Feist5b4aa862018-08-16 14:07:01 -0700157 nlohmann::json& zones = configRoot["FanZones"];
158 zones["@odata.id"] =
159 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
160 zones["@odata.type"] = "#OemManager.FanZones";
161 zones["@odata.context"] =
162 "/redfish/v1/$metadata#OemManager.FanZones";
163 configRoot["@odata.id"] =
164 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
165 configRoot["@odata.type"] = "#OemManager.Fan";
166 configRoot["@odata.context"] =
167 "/redfish/v1/$metadata#OemManager.Fan";
168
James Feist5b4aa862018-08-16 14:07:01 -0700169 for (const auto& pathPair : managedObj)
170 {
171 for (const auto& intfPair : pathPair.second)
172 {
173 if (intfPair.first != pidConfigurationIface &&
James Feistb7a08d02018-12-11 14:55:37 -0800174 intfPair.first != pidZoneConfigurationIface &&
175 intfPair.first != stepwiseConfigurationIface)
James Feist5b4aa862018-08-16 14:07:01 -0700176 {
177 continue;
178 }
179 auto findName = intfPair.second.find("Name");
180 if (findName == intfPair.second.end())
181 {
182 BMCWEB_LOG_ERROR << "Pid Field missing Name";
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800183 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700184 return;
185 }
186 const std::string* namePtr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800187 std::get_if<std::string>(&findName->second);
James Feist5b4aa862018-08-16 14:07:01 -0700188 if (namePtr == nullptr)
189 {
190 BMCWEB_LOG_ERROR << "Pid Name Field illegal";
James Feistb7a08d02018-12-11 14:55:37 -0800191 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700192 return;
193 }
194
195 std::string name = *namePtr;
196 dbus::utility::escapePathForDbus(name);
James Feistb7a08d02018-12-11 14:55:37 -0800197 nlohmann::json* config = nullptr;
James Feist5b4aa862018-08-16 14:07:01 -0700198 if (intfPair.first == pidZoneConfigurationIface)
199 {
200 std::string chassis;
201 if (!dbus::utility::getNthStringFromPath(
202 pathPair.first.str, 5, chassis))
203 {
204 chassis = "#IllegalValue";
205 }
206 nlohmann::json& zone = zones[name];
207 zone["Chassis"] = {
208 {"@odata.id", "/redfish/v1/Chassis/" + chassis}};
209 zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/"
210 "OpenBmc/Fan/FanZones/" +
211 name;
212 zone["@odata.type"] = "#OemManager.FanZone";
213 zone["@odata.context"] =
214 "/redfish/v1/$metadata#OemManager.FanZone";
James Feistb7a08d02018-12-11 14:55:37 -0800215 config = &zone;
James Feist5b4aa862018-08-16 14:07:01 -0700216 }
217
James Feistb7a08d02018-12-11 14:55:37 -0800218 else if (intfPair.first == stepwiseConfigurationIface)
219 {
220 nlohmann::json& controller = stepwise[name];
221 config = &controller;
222
223 controller["@odata.id"] =
224 "/redfish/v1/Managers/bmc#/Oem/"
225 "OpenBmc/Fan/StepwiseControllers/" +
226 std::string(name);
227 controller["@odata.type"] =
228 "#OemManager.StepwiseController";
229
230 controller["@odata.context"] =
231 "/redfish/v1/"
232 "$metadata#OemManager.StepwiseController";
233 }
234
235 // pid and fans are off the same configuration
236 else if (intfPair.first == pidConfigurationIface)
237 {
238 const std::string* classPtr = nullptr;
239 auto findClass = intfPair.second.find("Class");
240 if (findClass != intfPair.second.end())
241 {
Ed Tanousabf2add2019-01-22 16:40:12 -0800242 classPtr =
243 std::get_if<std::string>(&findClass->second);
James Feistb7a08d02018-12-11 14:55:37 -0800244 }
245 if (classPtr == nullptr)
246 {
247 BMCWEB_LOG_ERROR << "Pid Class Field illegal";
248 messages::internalError(asyncResp->res);
249 return;
250 }
251 bool isFan = *classPtr == "fan";
252 nlohmann::json& element =
253 isFan ? fans[name] : pids[name];
254 config = &element;
255 if (isFan)
256 {
257 element["@odata.id"] =
258 "/redfish/v1/Managers/bmc#/Oem/"
259 "OpenBmc/Fan/FanControllers/" +
260 std::string(name);
261 element["@odata.type"] =
262 "#OemManager.FanController";
263
264 element["@odata.context"] =
265 "/redfish/v1/"
266 "$metadata#OemManager.FanController";
267 }
268 else
269 {
270 element["@odata.id"] =
271 "/redfish/v1/Managers/bmc#/Oem/"
272 "OpenBmc/Fan/PidControllers/" +
273 std::string(name);
274 element["@odata.type"] =
275 "#OemManager.PidController";
276 element["@odata.context"] =
277 "/redfish/v1/$metadata"
278 "#OemManager.PidController";
279 }
280 }
281 else
282 {
283 BMCWEB_LOG_ERROR << "Unexpected configuration";
284 messages::internalError(asyncResp->res);
285 return;
286 }
287
288 // used for making maps out of 2 vectors
289 const std::vector<double>* keys = nullptr;
290 const std::vector<double>* values = nullptr;
291
James Feist5b4aa862018-08-16 14:07:01 -0700292 for (const auto& propertyPair : intfPair.second)
293 {
294 if (propertyPair.first == "Type" ||
295 propertyPair.first == "Class" ||
296 propertyPair.first == "Name")
297 {
298 continue;
299 }
300
301 // zones
302 if (intfPair.first == pidZoneConfigurationIface)
303 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800304 const double* ptr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800305 std::get_if<double>(&propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700306 if (ptr == nullptr)
307 {
308 BMCWEB_LOG_ERROR << "Field Illegal "
309 << propertyPair.first;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700310 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700311 return;
312 }
James Feistb7a08d02018-12-11 14:55:37 -0800313 (*config)[propertyPair.first] = *ptr;
314 }
315
316 if (intfPair.first == stepwiseConfigurationIface)
317 {
318 if (propertyPair.first == "Reading" ||
319 propertyPair.first == "Output")
320 {
321 const std::vector<double>* ptr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800322 std::get_if<std::vector<double>>(
James Feistb7a08d02018-12-11 14:55:37 -0800323 &propertyPair.second);
324
325 if (ptr == nullptr)
326 {
327 BMCWEB_LOG_ERROR << "Field Illegal "
328 << propertyPair.first;
329 messages::internalError(asyncResp->res);
330 return;
331 }
332
333 if (propertyPair.first == "Reading")
334 {
335 keys = ptr;
336 }
337 else
338 {
339 values = ptr;
340 }
341 if (keys && values)
342 {
343 if (keys->size() != values->size())
344 {
345 BMCWEB_LOG_ERROR
346 << "Reading and Output size don't "
347 "match ";
348 messages::internalError(asyncResp->res);
349 return;
350 }
351 nlohmann::json& steps = (*config)["Steps"];
352 steps = nlohmann::json::array();
353 for (size_t ii = 0; ii < keys->size(); ii++)
354 {
355 steps.push_back(
356 {{"Target", (*keys)[ii]},
357 {"Output", (*values)[ii]}});
358 }
359 }
360 }
361 if (propertyPair.first == "NegativeHysteresis" ||
362 propertyPair.first == "PositiveHysteresis")
363 {
364 const double* ptr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800365 std::get_if<double>(&propertyPair.second);
James Feistb7a08d02018-12-11 14:55:37 -0800366 if (ptr == nullptr)
367 {
368 BMCWEB_LOG_ERROR << "Field Illegal "
369 << propertyPair.first;
370 messages::internalError(asyncResp->res);
371 return;
372 }
373 (*config)[propertyPair.first] = *ptr;
374 }
James Feist5b4aa862018-08-16 14:07:01 -0700375 }
376
377 // pid and fans are off the same configuration
James Feistb7a08d02018-12-11 14:55:37 -0800378 if (intfPair.first == pidConfigurationIface ||
379 intfPair.first == stepwiseConfigurationIface)
James Feist5b4aa862018-08-16 14:07:01 -0700380 {
James Feist5b4aa862018-08-16 14:07:01 -0700381
382 if (propertyPair.first == "Zones")
383 {
384 const std::vector<std::string>* inputs =
Ed Tanousabf2add2019-01-22 16:40:12 -0800385 std::get_if<std::vector<std::string>>(
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800386 &propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700387
388 if (inputs == nullptr)
389 {
390 BMCWEB_LOG_ERROR
391 << "Zones Pid Field Illegal";
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800392 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700393 return;
394 }
James Feistb7a08d02018-12-11 14:55:37 -0800395 auto& data = (*config)[propertyPair.first];
James Feist5b4aa862018-08-16 14:07:01 -0700396 data = nlohmann::json::array();
397 for (std::string itemCopy : *inputs)
398 {
399 dbus::utility::escapePathForDbus(itemCopy);
400 data.push_back(
401 {{"@odata.id",
402 "/redfish/v1/Managers/bmc#/Oem/"
403 "OpenBmc/Fan/FanZones/" +
404 itemCopy}});
405 }
406 }
407 // todo(james): may never happen, but this
408 // assumes configuration data referenced in the
409 // PID config is provided by the same daemon, we
410 // could add another loop to cover all cases,
411 // but I'm okay kicking this can down the road a
412 // bit
413
414 else if (propertyPair.first == "Inputs" ||
415 propertyPair.first == "Outputs")
416 {
James Feistb7a08d02018-12-11 14:55:37 -0800417 auto& data = (*config)[propertyPair.first];
James Feist5b4aa862018-08-16 14:07:01 -0700418 const std::vector<std::string>* inputs =
Ed Tanousabf2add2019-01-22 16:40:12 -0800419 std::get_if<std::vector<std::string>>(
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800420 &propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700421
422 if (inputs == nullptr)
423 {
424 BMCWEB_LOG_ERROR << "Field Illegal "
425 << propertyPair.first;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700426 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700427 return;
428 }
429 data = *inputs;
430 } // doubles
431 else if (propertyPair.first ==
432 "FFGainCoefficient" ||
433 propertyPair.first == "FFOffCoefficient" ||
434 propertyPair.first == "ICoefficient" ||
435 propertyPair.first == "ILimitMax" ||
436 propertyPair.first == "ILimitMin" ||
James Feistaad1a252019-02-19 10:13:52 -0800437 propertyPair.first ==
438 "PositiveHysteresis" ||
439 propertyPair.first ==
440 "NegativeHysteresis" ||
James Feist5b4aa862018-08-16 14:07:01 -0700441 propertyPair.first == "OutLimitMax" ||
442 propertyPair.first == "OutLimitMin" ||
443 propertyPair.first == "PCoefficient" ||
James Feist7625cb82019-01-23 11:58:21 -0800444 propertyPair.first == "SetPoint" ||
James Feist5b4aa862018-08-16 14:07:01 -0700445 propertyPair.first == "SlewNeg" ||
446 propertyPair.first == "SlewPos")
447 {
448 const double* ptr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800449 std::get_if<double>(&propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700450 if (ptr == nullptr)
451 {
452 BMCWEB_LOG_ERROR << "Field Illegal "
453 << propertyPair.first;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700454 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700455 return;
456 }
James Feistb7a08d02018-12-11 14:55:37 -0800457 (*config)[propertyPair.first] = *ptr;
James Feist5b4aa862018-08-16 14:07:01 -0700458 }
459 }
460 }
461 }
462 }
463 },
464 connection, path, objectManagerIface, "GetManagedObjects");
465}
Jennifer Leeca537922018-08-10 10:07:30 -0700466
James Feist83ff9ab2018-08-31 10:18:24 -0700467enum class CreatePIDRet
468{
469 fail,
470 del,
471 patch
472};
473
James Feist5f2caae2018-12-12 14:08:25 -0800474static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response,
475 std::vector<nlohmann::json>& config,
476 std::vector<std::string>& zones)
477{
478
479 for (auto& odata : config)
480 {
481 std::string path;
482 if (!redfish::json_util::readJson(odata, response->res, "@odata.id",
483 path))
484 {
485 return false;
486 }
487 std::string input;
488 if (!dbus::utility::getNthStringFromPath(path, 4, input))
489 {
490 BMCWEB_LOG_ERROR << "Got invalid path " << path;
491 BMCWEB_LOG_ERROR << "Illegal Type Zones";
492 messages::propertyValueFormatError(response->res, odata.dump(),
493 "Zones");
494 return false;
495 }
496 boost::replace_all(input, "_", " ");
497 zones.emplace_back(std::move(input));
498 }
499 return true;
500}
501
James Feist83ff9ab2018-08-31 10:18:24 -0700502static CreatePIDRet createPidInterface(
503 const std::shared_ptr<AsyncResp>& response, const std::string& type,
James Feist5f2caae2018-12-12 14:08:25 -0800504 nlohmann::json&& record, const std::string& path,
James Feist83ff9ab2018-08-31 10:18:24 -0700505 const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
506 boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
507 output,
508 std::string& chassis)
509{
510
James Feist5f2caae2018-12-12 14:08:25 -0800511 // common deleter
512 if (record == nullptr)
513 {
514 std::string iface;
515 if (type == "PidControllers" || type == "FanControllers")
516 {
517 iface = pidConfigurationIface;
518 }
519 else if (type == "FanZones")
520 {
521 iface = pidZoneConfigurationIface;
522 }
523 else if (type == "StepwiseControllers")
524 {
525 iface = stepwiseConfigurationIface;
526 }
527 else
528 {
529 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type "
530 << type;
531 messages::propertyUnknown(response->res, type);
532 return CreatePIDRet::fail;
533 }
534 // delete interface
535 crow::connections::systemBus->async_method_call(
536 [response, path](const boost::system::error_code ec) {
537 if (ec)
538 {
539 BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec;
540 messages::internalError(response->res);
541 }
542 },
543 "xyz.openbmc_project.EntityManager", path, iface, "Delete");
544 return CreatePIDRet::del;
545 }
546
James Feist83ff9ab2018-08-31 10:18:24 -0700547 if (type == "PidControllers" || type == "FanControllers")
548 {
549 if (createNewObject)
550 {
551 output["Class"] = type == "PidControllers" ? std::string("temp")
552 : std::string("fan");
553 output["Type"] = std::string("Pid");
554 }
James Feist5f2caae2018-12-12 14:08:25 -0800555
556 std::optional<std::vector<nlohmann::json>> zones;
557 std::optional<std::vector<std::string>> inputs;
558 std::optional<std::vector<std::string>> outputs;
559 std::map<std::string, std::optional<double>> doubles;
560 if (!redfish::json_util::readJson(
561 record, response->res, "Inputs", inputs, "Outputs", outputs,
562 "Zones", zones, "FFGainCoefficient",
563 doubles["FFGainCoefficient"], "FFOffCoefficient",
564 doubles["FFOffCoefficient"], "ICoefficient",
565 doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"],
566 "ILimitMin", doubles["ILimitMin"], "OutLimitMax",
567 doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"],
568 "PCoefficient", doubles["PCoefficient"], "SetPoint",
569 doubles["SetPoint"], "SlewNeg", doubles["SlewNeg"], "SlewPos",
James Feistaad1a252019-02-19 10:13:52 -0800570 doubles["SlewPos"], "PositiveHysteresis",
571 doubles["PositiveHysteresis"], "NegativeHysteresis",
572 doubles["NegativeHysteresis"]))
James Feist83ff9ab2018-08-31 10:18:24 -0700573 {
James Feist5f2caae2018-12-12 14:08:25 -0800574 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
575 << record.dump();
576 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -0700577 }
James Feist5f2caae2018-12-12 14:08:25 -0800578 if (zones)
James Feist83ff9ab2018-08-31 10:18:24 -0700579 {
James Feist5f2caae2018-12-12 14:08:25 -0800580 std::vector<std::string> zonesStr;
581 if (!getZonesFromJsonReq(response, *zones, zonesStr))
James Feist83ff9ab2018-08-31 10:18:24 -0700582 {
James Feist5f2caae2018-12-12 14:08:25 -0800583 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones";
584 return CreatePIDRet::fail;
James Feist83ff9ab2018-08-31 10:18:24 -0700585 }
James Feist5f2caae2018-12-12 14:08:25 -0800586 output["Zones"] = std::move(zonesStr);
587 }
588 if (inputs || outputs)
589 {
590 std::array<std::optional<std::vector<std::string>>*, 2> containers =
591 {&inputs, &outputs};
592 size_t index = 0;
593 for (const auto& containerPtr : containers)
James Feist83ff9ab2018-08-31 10:18:24 -0700594 {
James Feist5f2caae2018-12-12 14:08:25 -0800595 std::optional<std::vector<std::string>>& container =
596 *containerPtr;
597 if (!container)
James Feist83ff9ab2018-08-31 10:18:24 -0700598 {
James Feist5f2caae2018-12-12 14:08:25 -0800599 index++;
600 continue;
James Feist83ff9ab2018-08-31 10:18:24 -0700601 }
James Feist5f2caae2018-12-12 14:08:25 -0800602
603 for (std::string& value : *container)
James Feist83ff9ab2018-08-31 10:18:24 -0700604 {
James Feist83ff9ab2018-08-31 10:18:24 -0700605
James Feist83ff9ab2018-08-31 10:18:24 -0700606 // try to find the sensor in the
607 // configuration
608 if (chassis.empty())
609 {
James Feist5f2caae2018-12-12 14:08:25 -0800610 std::string escaped =
611 boost::replace_all_copy(value, " ", "_");
James Feist83ff9ab2018-08-31 10:18:24 -0700612 std::find_if(
613 managedObj.begin(), managedObj.end(),
James Feist5f2caae2018-12-12 14:08:25 -0800614 [&chassis, &escaped](const auto& obj) {
James Feist83ff9ab2018-08-31 10:18:24 -0700615 if (boost::algorithm::ends_with(obj.first.str,
James Feist5f2caae2018-12-12 14:08:25 -0800616 escaped))
James Feist83ff9ab2018-08-31 10:18:24 -0700617 {
618 return dbus::utility::getNthStringFromPath(
619 obj.first.str, 5, chassis);
620 }
621 return false;
622 });
623 }
James Feist5f2caae2018-12-12 14:08:25 -0800624 boost::replace_all(value, "_", " ");
James Feist83ff9ab2018-08-31 10:18:24 -0700625 }
James Feist5f2caae2018-12-12 14:08:25 -0800626 std::string key;
627 if (index == 0)
James Feist83ff9ab2018-08-31 10:18:24 -0700628 {
James Feist5f2caae2018-12-12 14:08:25 -0800629 key = "Inputs";
James Feist83ff9ab2018-08-31 10:18:24 -0700630 }
James Feist5f2caae2018-12-12 14:08:25 -0800631 else
632 {
633 key = "Outputs";
634 }
635 output[key] = *container;
636 index++;
James Feist83ff9ab2018-08-31 10:18:24 -0700637 }
James Feist5f2caae2018-12-12 14:08:25 -0800638 }
James Feist83ff9ab2018-08-31 10:18:24 -0700639
James Feist5f2caae2018-12-12 14:08:25 -0800640 // doubles
641 for (const auto& pairs : doubles)
642 {
643 if (!pairs.second)
James Feist83ff9ab2018-08-31 10:18:24 -0700644 {
James Feist5f2caae2018-12-12 14:08:25 -0800645 continue;
James Feist83ff9ab2018-08-31 10:18:24 -0700646 }
James Feist5f2caae2018-12-12 14:08:25 -0800647 BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second;
648 output[pairs.first] = *(pairs.second);
James Feist83ff9ab2018-08-31 10:18:24 -0700649 }
650 }
James Feist5f2caae2018-12-12 14:08:25 -0800651
James Feist83ff9ab2018-08-31 10:18:24 -0700652 else if (type == "FanZones")
653 {
James Feist83ff9ab2018-08-31 10:18:24 -0700654 output["Type"] = std::string("Pid.Zone");
655
James Feist5f2caae2018-12-12 14:08:25 -0800656 std::optional<nlohmann::json> chassisContainer;
657 std::optional<double> failSafePercent;
658 std::optional<double> minThermalRpm;
659 if (!redfish::json_util::readJson(record, response->res, "Chassis",
660 chassisContainer, "FailSafePercent",
661 failSafePercent, "MinThermalRpm",
662 minThermalRpm))
James Feist83ff9ab2018-08-31 10:18:24 -0700663 {
James Feist5f2caae2018-12-12 14:08:25 -0800664 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
665 << record.dump();
666 return CreatePIDRet::fail;
667 }
James Feist83ff9ab2018-08-31 10:18:24 -0700668
James Feist5f2caae2018-12-12 14:08:25 -0800669 if (chassisContainer)
670 {
671
672 std::string chassisId;
673 if (!redfish::json_util::readJson(*chassisContainer, response->res,
674 "@odata.id", chassisId))
James Feist83ff9ab2018-08-31 10:18:24 -0700675 {
James Feist5f2caae2018-12-12 14:08:25 -0800676 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
677 << chassisContainer->dump();
James Feist83ff9ab2018-08-31 10:18:24 -0700678 return CreatePIDRet::fail;
679 }
James Feist5f2caae2018-12-12 14:08:25 -0800680
681 // /refish/v1/chassis/chassis_name/
682 if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis))
683 {
684 BMCWEB_LOG_ERROR << "Got invalid path " << chassisId;
685 messages::invalidObject(response->res, chassisId);
686 return CreatePIDRet::fail;
687 }
688 }
689 if (minThermalRpm)
690 {
691 output["MinThermalRpm"] = *minThermalRpm;
692 }
693 if (failSafePercent)
694 {
695 output["FailSafePercent"] = *failSafePercent;
696 }
697 }
698 else if (type == "StepwiseControllers")
699 {
700 output["Type"] = std::string("Stepwise");
701
702 std::optional<std::vector<nlohmann::json>> zones;
703 std::optional<std::vector<nlohmann::json>> steps;
704 std::optional<std::vector<std::string>> inputs;
705 std::optional<double> positiveHysteresis;
706 std::optional<double> negativeHysteresis;
707 if (!redfish::json_util::readJson(
708 record, response->res, "Zones", zones, "Steps", steps, "Inputs",
709 inputs, "PositiveHysteresis", positiveHysteresis,
710 "NegativeHysteresis", negativeHysteresis))
711 {
712 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
713 << record.dump();
714 return CreatePIDRet::fail;
715 }
716
717 if (zones)
718 {
719 std::vector<std::string> zoneStrs;
720 if (!getZonesFromJsonReq(response, *zones, zoneStrs))
721 {
722 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones";
723 return CreatePIDRet::fail;
724 }
725 output["Zones"] = std::move(zoneStrs);
726 }
727 if (steps)
728 {
729 std::vector<double> readings;
730 std::vector<double> outputs;
731 for (auto& step : *steps)
732 {
733 double target;
734 double output;
735
736 if (!redfish::json_util::readJson(step, response->res, "Target",
737 target, "Output", output))
738 {
739 BMCWEB_LOG_ERROR << "Line:" << __LINE__
740 << ", Illegal Property " << record.dump();
741 return CreatePIDRet::fail;
742 }
743 readings.emplace_back(target);
744 outputs.emplace_back(output);
745 }
746 output["Reading"] = std::move(readings);
747 output["Output"] = std::move(outputs);
748 }
749 if (inputs)
750 {
751 for (std::string& value : *inputs)
752 {
753 if (chassis.empty())
754 {
755 std::string escaped =
756 boost::replace_all_copy(value, " ", "_");
757 std::find_if(
758 managedObj.begin(), managedObj.end(),
759 [&chassis, &escaped](const auto& obj) {
760 if (boost::algorithm::ends_with(obj.first.str,
761 escaped))
762 {
763 return dbus::utility::getNthStringFromPath(
764 obj.first.str, 5, chassis);
765 }
766 return false;
767 });
768 }
769 boost::replace_all(value, "_", " ");
770 }
771 output["Inputs"] = std::move(*inputs);
772 }
773 if (negativeHysteresis)
774 {
775 output["NegativeHysteresis"] = *negativeHysteresis;
776 }
777 if (positiveHysteresis)
778 {
779 output["PositiveHysteresis"] = *positiveHysteresis;
James Feist83ff9ab2018-08-31 10:18:24 -0700780 }
781 }
782 else
783 {
James Feist5f2caae2018-12-12 14:08:25 -0800784 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type;
Jason M. Bills35a62c72018-10-09 12:45:45 -0700785 messages::propertyUnknown(response->res, type);
James Feist83ff9ab2018-08-31 10:18:24 -0700786 return CreatePIDRet::fail;
787 }
788 return CreatePIDRet::patch;
789}
790
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791class Manager : public Node
792{
793 public:
James Feist5b4aa862018-08-16 14:07:01 -0700794 Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800796 uuid = app.template getMiddleware<crow::persistent_data::Middleware>()
797 .systemUuid;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 entityPrivileges = {
799 {boost::beast::http::verb::get, {{"Login"}}},
800 {boost::beast::http::verb::head, {{"Login"}}},
801 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
802 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
803 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
804 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100805 }
806
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 private:
James Feist5b4aa862018-08-16 14:07:01 -0700808 void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
809 {
810 crow::connections::systemBus->async_method_call(
811 [asyncResp](const boost::system::error_code ec,
812 const crow::openbmc_mapper::GetSubTreeType& subtree) {
813 if (ec)
814 {
815 BMCWEB_LOG_ERROR << ec;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700816 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700817 return;
818 }
819
820 // create map of <connection, path to objMgr>>
821 boost::container::flat_map<std::string, std::string>
822 objectMgrPaths;
James Feist6bce33b2018-10-22 12:05:56 -0700823 boost::container::flat_set<std::string> calledConnections;
James Feist5b4aa862018-08-16 14:07:01 -0700824 for (const auto& pathGroup : subtree)
825 {
826 for (const auto& connectionGroup : pathGroup.second)
827 {
James Feist6bce33b2018-10-22 12:05:56 -0700828 auto findConnection =
829 calledConnections.find(connectionGroup.first);
830 if (findConnection != calledConnections.end())
831 {
832 break;
833 }
James Feist5b4aa862018-08-16 14:07:01 -0700834 for (const std::string& interface :
835 connectionGroup.second)
836 {
837 if (interface == objectManagerIface)
838 {
839 objectMgrPaths[connectionGroup.first] =
840 pathGroup.first;
841 }
842 // this list is alphabetical, so we
843 // should have found the objMgr by now
844 if (interface == pidConfigurationIface ||
James Feistb7a08d02018-12-11 14:55:37 -0800845 interface == pidZoneConfigurationIface ||
846 interface == stepwiseConfigurationIface)
James Feist5b4aa862018-08-16 14:07:01 -0700847 {
848 auto findObjMgr =
849 objectMgrPaths.find(connectionGroup.first);
850 if (findObjMgr == objectMgrPaths.end())
851 {
852 BMCWEB_LOG_DEBUG << connectionGroup.first
853 << "Has no Object Manager";
854 continue;
855 }
James Feist6bce33b2018-10-22 12:05:56 -0700856
857 calledConnections.insert(connectionGroup.first);
858
James Feist5b4aa862018-08-16 14:07:01 -0700859 asyncPopulatePid(findObjMgr->first,
860 findObjMgr->second, asyncResp);
861 break;
862 }
863 }
864 }
865 }
866 },
867 "xyz.openbmc_project.ObjectMapper",
868 "/xyz/openbmc_project/object_mapper",
869 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
James Feistb7a08d02018-12-11 14:55:37 -0800870 std::array<const char*, 4>{
871 pidConfigurationIface, pidZoneConfigurationIface,
872 objectManagerIface, stepwiseConfigurationIface});
James Feist5b4aa862018-08-16 14:07:01 -0700873 }
874
875 void doGet(crow::Response& res, const crow::Request& req,
876 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800878 res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc";
879 res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager";
880 res.jsonValue["@odata.context"] =
881 "/redfish/v1/$metadata#Manager.Manager";
882 res.jsonValue["Id"] = "bmc";
883 res.jsonValue["Name"] = "OpenBmc Manager";
884 res.jsonValue["Description"] = "Baseboard Management Controller";
885 res.jsonValue["PowerState"] = "On";
Ed Tanous029573d2019-02-01 10:57:49 -0800886 res.jsonValue["Status"] = {{"State", "Enabled"}, {"Health", "OK"}};
Ed Tanous0f74e642018-11-12 15:17:05 -0800887 res.jsonValue["ManagerType"] = "BMC";
Ed Tanous75176582018-12-14 08:14:34 -0800888 res.jsonValue["UUID"] = uuid;
889 res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model
Ed Tanous0f74e642018-11-12 15:17:05 -0800890
891 res.jsonValue["LogServices"] = {
892 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}};
893
894 res.jsonValue["NetworkProtocol"] = {
895 {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}};
896
897 res.jsonValue["EthernetInterfaces"] = {
898 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
899 // default oem data
900 nlohmann::json& oem = res.jsonValue["Oem"];
901 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
902 oem["@odata.type"] = "#OemManager.Oem";
903 oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
904 oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
905 oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
906 oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
907 oemOpenbmc["@odata.context"] =
908 "/redfish/v1/$metadata#OemManager.OpenBmc";
909
Jennifer Leeed5befb2018-08-10 11:29:45 -0700910 // Update Actions object.
Ed Tanous0f74e642018-11-12 15:17:05 -0800911 nlohmann::json& manager_reset =
912 res.jsonValue["Actions"]["#Manager.Reset"];
Jennifer Leeed5befb2018-08-10 11:29:45 -0700913 manager_reset["target"] =
914 "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
915 manager_reset["ResetType@Redfish.AllowableValues"] = {
916 "GracefulRestart"};
Jennifer Leeca537922018-08-10 10:07:30 -0700917
Ed Tanous0f74e642018-11-12 15:17:05 -0800918 res.jsonValue["DateTime"] = getDateTime();
Ed Tanous029573d2019-02-01 10:57:49 -0800919 res.jsonValue["Links"] = {
920 {"ManagerForServers@odata.count", 1},
921 {"ManagerForServers",
922 {{{"@odata.id", "/redfish/v1/Systems/system"}}}},
923 {"ManagerForServers", nlohmann::json::array()}};
Jennifer Leeed5befb2018-08-10 11:29:45 -0700924 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
James Feist5b4aa862018-08-16 14:07:01 -0700925
Jennifer Leeca537922018-08-10 10:07:30 -0700926 crow::connections::systemBus->async_method_call(
927 [asyncResp](const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -0700928 const dbus::utility::ManagedObjectType& resp) {
Jennifer Leeca537922018-08-10 10:07:30 -0700929 if (ec)
930 {
931 BMCWEB_LOG_ERROR << "Error while getting Software Version";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700932 messages::internalError(asyncResp->res);
Jennifer Leeca537922018-08-10 10:07:30 -0700933 return;
934 }
935
James Feist5b4aa862018-08-16 14:07:01 -0700936 for (auto& objpath : resp)
Jennifer Leeca537922018-08-10 10:07:30 -0700937 {
James Feist5b4aa862018-08-16 14:07:01 -0700938 for (auto& interface : objpath.second)
Jennifer Leeca537922018-08-10 10:07:30 -0700939 {
James Feist5f2caae2018-12-12 14:08:25 -0800940 // If interface is
941 // xyz.openbmc_project.Software.Version, this is
942 // what we're looking for.
Jennifer Leeca537922018-08-10 10:07:30 -0700943 if (interface.first ==
944 "xyz.openbmc_project.Software.Version")
945 {
946 // Cut out everyting until last "/", ...
James Feist5b4aa862018-08-16 14:07:01 -0700947 for (auto& property : interface.second)
Jennifer Leeca537922018-08-10 10:07:30 -0700948 {
949 if (property.first == "Version")
950 {
James Feist5b4aa862018-08-16 14:07:01 -0700951 const std::string* value =
Ed Tanousabf2add2019-01-22 16:40:12 -0800952 std::get_if<std::string>(
953 &property.second);
Jennifer Leeca537922018-08-10 10:07:30 -0700954 if (value == nullptr)
955 {
956 continue;
957 }
958 asyncResp->res
959 .jsonValue["FirmwareVersion"] = *value;
960 }
961 }
962 }
963 }
964 }
965 },
966 "xyz.openbmc_project.Software.BMC.Updater",
967 "/xyz/openbmc_project/software",
968 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist5b4aa862018-08-16 14:07:01 -0700969 getPidValues(asyncResp);
970 }
James Feist5f2caae2018-12-12 14:08:25 -0800971 void setPidValues(std::shared_ptr<AsyncResp> response, nlohmann::json& data)
James Feist83ff9ab2018-08-31 10:18:24 -0700972 {
James Feist5f2caae2018-12-12 14:08:25 -0800973
James Feist83ff9ab2018-08-31 10:18:24 -0700974 // todo(james): might make sense to do a mapper call here if this
975 // interface gets more traction
976 crow::connections::systemBus->async_method_call(
977 [response,
978 data](const boost::system::error_code ec,
979 const dbus::utility::ManagedObjectType& managedObj) {
980 if (ec)
981 {
982 BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
Jason M. Bills35a62c72018-10-09 12:45:45 -0700983 messages::internalError(response->res);
James Feist83ff9ab2018-08-31 10:18:24 -0700984 return;
985 }
James Feist5f2caae2018-12-12 14:08:25 -0800986
987 // todo(james) mutable doesn't work with asio bindings
988 nlohmann::json jsonData = data;
989
990 std::optional<nlohmann::json> pidControllers;
991 std::optional<nlohmann::json> fanControllers;
992 std::optional<nlohmann::json> fanZones;
993 std::optional<nlohmann::json> stepwiseControllers;
994 if (!redfish::json_util::readJson(
995 jsonData, response->res, "PidControllers",
996 pidControllers, "FanControllers", fanControllers,
997 "FanZones", fanZones, "StepwiseControllers",
998 stepwiseControllers))
James Feist83ff9ab2018-08-31 10:18:24 -0700999 {
James Feist5f2caae2018-12-12 14:08:25 -08001000 BMCWEB_LOG_ERROR << "Line:" << __LINE__
1001 << ", Illegal Property "
1002 << jsonData.dump();
1003 return;
1004 }
1005 std::array<
Ed Tanous43b761d2019-02-13 20:10:56 -08001006 std::pair<std::string, std::optional<nlohmann::json>*>, 4>
James Feist5f2caae2018-12-12 14:08:25 -08001007 sections = {
1008 std::make_pair("PidControllers", &pidControllers),
1009 std::make_pair("FanControllers", &fanControllers),
1010 std::make_pair("FanZones", &fanZones),
1011 std::make_pair("StepwiseControllers",
1012 &stepwiseControllers)};
1013
1014 for (auto& containerPair : sections)
1015 {
1016 auto& container = *(containerPair.second);
1017 if (!container)
James Feist83ff9ab2018-08-31 10:18:24 -07001018 {
James Feist5f2caae2018-12-12 14:08:25 -08001019 continue;
James Feist83ff9ab2018-08-31 10:18:24 -07001020 }
Ed Tanous43b761d2019-02-13 20:10:56 -08001021 std::string& type = containerPair.first;
James Feist5f2caae2018-12-12 14:08:25 -08001022
1023 for (auto& record : container->items())
James Feist83ff9ab2018-08-31 10:18:24 -07001024 {
James Feist5f2caae2018-12-12 14:08:25 -08001025 const auto& name = record.key();
James Feist83ff9ab2018-08-31 10:18:24 -07001026 auto pathItr =
1027 std::find_if(managedObj.begin(), managedObj.end(),
1028 [&name](const auto& obj) {
1029 return boost::algorithm::ends_with(
1030 obj.first.str, name);
1031 });
1032 boost::container::flat_map<
1033 std::string, dbus::utility::DbusVariantType>
1034 output;
1035
1036 output.reserve(16); // The pid interface length
1037
1038 // determines if we're patching entity-manager or
1039 // creating a new object
1040 bool createNewObject = (pathItr == managedObj.end());
James Feist5f2caae2018-12-12 14:08:25 -08001041 std::string iface;
1042 if (type == "PidControllers" ||
1043 type == "FanControllers")
James Feist83ff9ab2018-08-31 10:18:24 -07001044 {
James Feist5f2caae2018-12-12 14:08:25 -08001045 iface = pidConfigurationIface;
James Feist83ff9ab2018-08-31 10:18:24 -07001046 if (!createNewObject &&
1047 pathItr->second.find(pidConfigurationIface) ==
1048 pathItr->second.end())
1049 {
1050 createNewObject = true;
1051 }
1052 }
James Feist5f2caae2018-12-12 14:08:25 -08001053 else if (type == "FanZones")
James Feist83ff9ab2018-08-31 10:18:24 -07001054 {
James Feist5f2caae2018-12-12 14:08:25 -08001055 iface = pidZoneConfigurationIface;
1056 if (!createNewObject &&
1057 pathItr->second.find(
1058 pidZoneConfigurationIface) ==
1059 pathItr->second.end())
1060 {
1061
1062 createNewObject = true;
1063 }
1064 }
1065 else if (type == "StepwiseControllers")
1066 {
1067 iface = stepwiseConfigurationIface;
1068 if (!createNewObject &&
1069 pathItr->second.find(
1070 stepwiseConfigurationIface) ==
1071 pathItr->second.end())
1072 {
1073 createNewObject = true;
1074 }
James Feist83ff9ab2018-08-31 10:18:24 -07001075 }
1076 output["Name"] =
1077 boost::replace_all_copy(name, "_", " ");
1078
1079 std::string chassis;
1080 CreatePIDRet ret = createPidInterface(
James Feist5f2caae2018-12-12 14:08:25 -08001081 response, type, std::move(record.value()),
James Feist83ff9ab2018-08-31 10:18:24 -07001082 pathItr->first.str, managedObj, createNewObject,
1083 output, chassis);
1084 if (ret == CreatePIDRet::fail)
1085 {
1086 return;
1087 }
1088 else if (ret == CreatePIDRet::del)
1089 {
1090 continue;
1091 }
1092
1093 if (!createNewObject)
1094 {
1095 for (const auto& property : output)
1096 {
James Feist83ff9ab2018-08-31 10:18:24 -07001097 crow::connections::systemBus->async_method_call(
1098 [response,
1099 propertyName{std::string(property.first)}](
1100 const boost::system::error_code ec) {
1101 if (ec)
1102 {
1103 BMCWEB_LOG_ERROR
1104 << "Error patching "
1105 << propertyName << ": " << ec;
Jason M. Bills35a62c72018-10-09 12:45:45 -07001106 messages::internalError(
1107 response->res);
James Feist83ff9ab2018-08-31 10:18:24 -07001108 }
1109 },
1110 "xyz.openbmc_project.EntityManager",
1111 pathItr->first.str,
1112 "org.freedesktop.DBus.Properties", "Set",
James Feist5f2caae2018-12-12 14:08:25 -08001113 iface, property.first, property.second);
James Feist83ff9ab2018-08-31 10:18:24 -07001114 }
1115 }
1116 else
1117 {
1118 if (chassis.empty())
1119 {
1120 BMCWEB_LOG_ERROR
1121 << "Failed to get chassis from config";
Jason M. Bills35a62c72018-10-09 12:45:45 -07001122 messages::invalidObject(response->res, name);
James Feist83ff9ab2018-08-31 10:18:24 -07001123 return;
1124 }
1125
1126 bool foundChassis = false;
1127 for (const auto& obj : managedObj)
1128 {
1129 if (boost::algorithm::ends_with(obj.first.str,
1130 chassis))
1131 {
1132 chassis = obj.first.str;
1133 foundChassis = true;
1134 break;
1135 }
1136 }
1137 if (!foundChassis)
1138 {
1139 BMCWEB_LOG_ERROR
1140 << "Failed to find chassis on dbus";
Jason M. Bills35a62c72018-10-09 12:45:45 -07001141 messages::resourceMissingAtURI(
1142 response->res,
1143 "/redfish/v1/Chassis/" + chassis);
James Feist83ff9ab2018-08-31 10:18:24 -07001144 return;
1145 }
1146
1147 crow::connections::systemBus->async_method_call(
1148 [response](const boost::system::error_code ec) {
1149 if (ec)
1150 {
1151 BMCWEB_LOG_ERROR
1152 << "Error Adding Pid Object " << ec;
Jason M. Bills35a62c72018-10-09 12:45:45 -07001153 messages::internalError(response->res);
James Feist83ff9ab2018-08-31 10:18:24 -07001154 }
1155 },
1156 "xyz.openbmc_project.EntityManager", chassis,
1157 "xyz.openbmc_project.AddObject", "AddObject",
1158 output);
1159 }
1160 }
1161 }
1162 },
1163 "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
1164 "GetManagedObjects");
1165 }
James Feist5b4aa862018-08-16 14:07:01 -07001166
1167 void doPatch(crow::Response& res, const crow::Request& req,
1168 const std::vector<std::string>& params) override
1169 {
Ed Tanous0627a2c2018-11-29 17:09:23 -08001170 std::optional<nlohmann::json> oem;
1171
1172 if (!json_util::readJson(req, res, "Oem", oem))
James Feist83ff9ab2018-08-31 10:18:24 -07001173 {
1174 return;
1175 }
Ed Tanous0627a2c2018-11-29 17:09:23 -08001176
James Feist83ff9ab2018-08-31 10:18:24 -07001177 std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001178
1179 if (oem)
James Feist83ff9ab2018-08-31 10:18:24 -07001180 {
Ed Tanous43b761d2019-02-13 20:10:56 -08001181 std::optional<nlohmann::json> openbmc;
1182 if (!redfish::json_util::readJson(*oem, res, "OpenBmc", openbmc))
James Feist83ff9ab2018-08-31 10:18:24 -07001183 {
Ed Tanous43b761d2019-02-13 20:10:56 -08001184 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
1185 << oem->dump();
1186 return;
1187 }
1188 if (openbmc)
1189 {
1190 std::optional<nlohmann::json> fan;
1191 if (!redfish::json_util::readJson(*openbmc, res, "Fan", fan))
James Feist83ff9ab2018-08-31 10:18:24 -07001192 {
James Feist5f2caae2018-12-12 14:08:25 -08001193 BMCWEB_LOG_ERROR << "Line:" << __LINE__
Ed Tanous43b761d2019-02-13 20:10:56 -08001194 << ", Illegal Property "
1195 << openbmc->dump();
James Feist5f2caae2018-12-12 14:08:25 -08001196 return;
1197 }
Ed Tanous43b761d2019-02-13 20:10:56 -08001198 if (fan)
James Feist5f2caae2018-12-12 14:08:25 -08001199 {
Ed Tanous43b761d2019-02-13 20:10:56 -08001200 setPidValues(response, *fan);
James Feist83ff9ab2018-08-31 10:18:24 -07001201 }
James Feist83ff9ab2018-08-31 10:18:24 -07001202 }
1203 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001204 }
1205
1206 std::string getDateTime() const
1207 {
1208 std::array<char, 128> dateTime;
1209 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
1210 std::time_t time = std::time(nullptr);
1211
1212 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
1213 std::localtime(&time)))
1214 {
1215 // insert the colon required by the ISO 8601 standard
1216 redfishDateTime = std::string(dateTime.data());
1217 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
1218 }
1219
1220 return redfishDateTime;
1221 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001222
1223 std::string uuid;
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001224};
1225
Ed Tanous1abe55e2018-09-05 08:30:59 -07001226class ManagerCollection : public Node
1227{
1228 public:
James Feist5b4aa862018-08-16 14:07:01 -07001229 ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001230 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001231 entityPrivileges = {
1232 {boost::beast::http::verb::get, {{"Login"}}},
1233 {boost::beast::http::verb::head, {{"Login"}}},
1234 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1235 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1236 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1237 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1238 }
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001239
Ed Tanous1abe55e2018-09-05 08:30:59 -07001240 private:
James Feist5b4aa862018-08-16 14:07:01 -07001241 void doGet(crow::Response& res, const crow::Request& req,
1242 const std::vector<std::string>& params) override
Ed Tanous1abe55e2018-09-05 08:30:59 -07001243 {
James Feist83ff9ab2018-08-31 10:18:24 -07001244 // Collections don't include the static data added by SubRoute
1245 // because it has a duplicate entry for members
Ed Tanous1abe55e2018-09-05 08:30:59 -07001246 res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
1247 res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
1248 res.jsonValue["@odata.context"] =
1249 "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
1250 res.jsonValue["Name"] = "Manager Collection";
1251 res.jsonValue["Members@odata.count"] = 1;
1252 res.jsonValue["Members"] = {
James Feist5b4aa862018-08-16 14:07:01 -07001253 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001254 res.end();
1255 }
Borawski.Lukasz9c3106852018-02-09 15:24:22 +01001256};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257} // namespace redfish