blob: f009f2a5b7fef5474a2937d51f9f0d1f8df8dd57 [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>
22
Ed Tanous1abe55e2018-09-05 08:30:59 -070023namespace redfish
24{
Jennifer Leeed5befb2018-08-10 11:29:45 -070025
26/**
27 * ManagerActionsReset class supports handle POST method for Reset action.
28 * The class retrieves and sends data directly to dbus.
29 */
30class ManagerActionsReset : public Node
31{
32 public:
33 ManagerActionsReset(CrowApp& app) :
34 Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/")
35 {
36 entityPrivileges = {
37 {boost::beast::http::verb::get, {{"Login"}}},
38 {boost::beast::http::verb::head, {{"Login"}}},
39 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
40 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
41 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
42 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
43 }
44
45 private:
46 /**
Jennifer Leeed5befb2018-08-10 11:29:45 -070047 * Function handles POST method request.
48 * Analyzes POST body message before sends Reset request data to dbus.
49 * OpenBMC allows for ResetType is GracefulRestart only.
50 */
51 void doPost(crow::Response& res, const crow::Request& req,
52 const std::vector<std::string>& params) override
53 {
54 std::string resetType;
55
56 if (!json_util::readJson(req, res, "ResetType", resetType))
57 {
58 return;
59 }
60
61 if (resetType != "GracefulRestart")
62 {
63 res.result(boost::beast::http::status::bad_request);
64 messages::actionParameterNotSupported(res, resetType, "ResetType");
65 BMCWEB_LOG_ERROR << "Request incorrect action parameter: "
66 << resetType;
67 res.end();
68 return;
69 }
70 doBMCGracefulRestart(res, req, params);
71 }
72
73 /**
74 * Function transceives data with dbus directly.
75 * All BMC state properties will be retrieved before sending reset request.
76 */
77 void doBMCGracefulRestart(crow::Response& res, const crow::Request& req,
78 const std::vector<std::string>& params)
79 {
80 const char* processName = "xyz.openbmc_project.State.BMC";
81 const char* objectPath = "/xyz/openbmc_project/state/bmc0";
82 const char* interfaceName = "xyz.openbmc_project.State.BMC";
83 const std::string& propertyValue =
84 "xyz.openbmc_project.State.BMC.Transition.Reboot";
85 const char* destProperty = "RequestedBMCTransition";
86
87 // Create the D-Bus variant for D-Bus call.
88 VariantType dbusPropertyValue(propertyValue);
89
90 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
91
92 crow::connections::systemBus->async_method_call(
93 [asyncResp](const boost::system::error_code ec) {
94 // Use "Set" method to set the property value.
95 if (ec)
96 {
97 BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec;
98 messages::internalError(asyncResp->res);
99 return;
100 }
101
102 messages::success(asyncResp->res);
103 },
104 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
105 interfaceName, destProperty, dbusPropertyValue);
106 }
107};
108
James Feist5b4aa862018-08-16 14:07:01 -0700109static constexpr const char* objectManagerIface =
110 "org.freedesktop.DBus.ObjectManager";
111static constexpr const char* pidConfigurationIface =
112 "xyz.openbmc_project.Configuration.Pid";
113static constexpr const char* pidZoneConfigurationIface =
114 "xyz.openbmc_project.Configuration.Pid.Zone";
James Feistb7a08d02018-12-11 14:55:37 -0800115static constexpr const char* stepwiseConfigurationIface =
116 "xyz.openbmc_project.Configuration.Stepwise";
Borawski.Lukasz9c3106852018-02-09 15:24:22 +0100117
James Feist5b4aa862018-08-16 14:07:01 -0700118static void asyncPopulatePid(const std::string& connection,
119 const std::string& path,
120 std::shared_ptr<AsyncResp> asyncResp)
121{
122
123 crow::connections::systemBus->async_method_call(
124 [asyncResp](const boost::system::error_code ec,
125 const dbus::utility::ManagedObjectType& managedObj) {
126 if (ec)
127 {
128 BMCWEB_LOG_ERROR << ec;
James Feist5b4aa862018-08-16 14:07:01 -0700129 asyncResp->res.jsonValue.clear();
Jason M. Billsf12894f2018-10-09 12:45:45 -0700130 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700131 return;
132 }
133 nlohmann::json& configRoot =
134 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
135 nlohmann::json& fans = configRoot["FanControllers"];
136 fans["@odata.type"] = "#OemManager.FanControllers";
137 fans["@odata.context"] =
138 "/redfish/v1/$metadata#OemManager.FanControllers";
139 fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/"
140 "Fan/FanControllers";
141
142 nlohmann::json& pids = configRoot["PidControllers"];
143 pids["@odata.type"] = "#OemManager.PidControllers";
144 pids["@odata.context"] =
145 "/redfish/v1/$metadata#OemManager.PidControllers";
146 pids["@odata.id"] =
147 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers";
148
James Feistb7a08d02018-12-11 14:55:37 -0800149 nlohmann::json& stepwise = configRoot["StepwiseControllers"];
150 stepwise["@odata.type"] = "#OemManager.StepwiseControllers";
151 stepwise["@odata.context"] =
152 "/redfish/v1/$metadata#OemManager.StepwiseControllers";
153 stepwise["@odata.id"] =
154 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers";
155
James Feist5b4aa862018-08-16 14:07:01 -0700156 nlohmann::json& zones = configRoot["FanZones"];
157 zones["@odata.id"] =
158 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones";
159 zones["@odata.type"] = "#OemManager.FanZones";
160 zones["@odata.context"] =
161 "/redfish/v1/$metadata#OemManager.FanZones";
162 configRoot["@odata.id"] =
163 "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan";
164 configRoot["@odata.type"] = "#OemManager.Fan";
165 configRoot["@odata.context"] =
166 "/redfish/v1/$metadata#OemManager.Fan";
167
168 bool propertyError = false;
169 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 Tanous1b6b96c2018-11-30 11:35:41 -0800187 sdbusplus::message::variant_ns::get_if<std::string>(
188 &findName->second);
James Feist5b4aa862018-08-16 14:07:01 -0700189 if (namePtr == nullptr)
190 {
191 BMCWEB_LOG_ERROR << "Pid Name Field illegal";
James Feistb7a08d02018-12-11 14:55:37 -0800192 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700193 return;
194 }
195
196 std::string name = *namePtr;
197 dbus::utility::escapePathForDbus(name);
James Feistb7a08d02018-12-11 14:55:37 -0800198 nlohmann::json* config = nullptr;
James Feist5b4aa862018-08-16 14:07:01 -0700199 if (intfPair.first == pidZoneConfigurationIface)
200 {
201 std::string chassis;
202 if (!dbus::utility::getNthStringFromPath(
203 pathPair.first.str, 5, chassis))
204 {
205 chassis = "#IllegalValue";
206 }
207 nlohmann::json& zone = zones[name];
208 zone["Chassis"] = {
209 {"@odata.id", "/redfish/v1/Chassis/" + chassis}};
210 zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/"
211 "OpenBmc/Fan/FanZones/" +
212 name;
213 zone["@odata.type"] = "#OemManager.FanZone";
214 zone["@odata.context"] =
215 "/redfish/v1/$metadata#OemManager.FanZone";
James Feistb7a08d02018-12-11 14:55:37 -0800216 config = &zone;
James Feist5b4aa862018-08-16 14:07:01 -0700217 }
218
James Feistb7a08d02018-12-11 14:55:37 -0800219 else if (intfPair.first == stepwiseConfigurationIface)
220 {
221 nlohmann::json& controller = stepwise[name];
222 config = &controller;
223
224 controller["@odata.id"] =
225 "/redfish/v1/Managers/bmc#/Oem/"
226 "OpenBmc/Fan/StepwiseControllers/" +
227 std::string(name);
228 controller["@odata.type"] =
229 "#OemManager.StepwiseController";
230
231 controller["@odata.context"] =
232 "/redfish/v1/"
233 "$metadata#OemManager.StepwiseController";
234 }
235
236 // pid and fans are off the same configuration
237 else if (intfPair.first == pidConfigurationIface)
238 {
239 const std::string* classPtr = nullptr;
240 auto findClass = intfPair.second.find("Class");
241 if (findClass != intfPair.second.end())
242 {
243 classPtr = sdbusplus::message::variant_ns::get_if<
244 std::string>(&findClass->second);
245 }
246 if (classPtr == nullptr)
247 {
248 BMCWEB_LOG_ERROR << "Pid Class Field illegal";
249 messages::internalError(asyncResp->res);
250 return;
251 }
252 bool isFan = *classPtr == "fan";
253 nlohmann::json& element =
254 isFan ? fans[name] : pids[name];
255 config = &element;
256 if (isFan)
257 {
258 element["@odata.id"] =
259 "/redfish/v1/Managers/bmc#/Oem/"
260 "OpenBmc/Fan/FanControllers/" +
261 std::string(name);
262 element["@odata.type"] =
263 "#OemManager.FanController";
264
265 element["@odata.context"] =
266 "/redfish/v1/"
267 "$metadata#OemManager.FanController";
268 }
269 else
270 {
271 element["@odata.id"] =
272 "/redfish/v1/Managers/bmc#/Oem/"
273 "OpenBmc/Fan/PidControllers/" +
274 std::string(name);
275 element["@odata.type"] =
276 "#OemManager.PidController";
277 element["@odata.context"] =
278 "/redfish/v1/$metadata"
279 "#OemManager.PidController";
280 }
281 }
282 else
283 {
284 BMCWEB_LOG_ERROR << "Unexpected configuration";
285 messages::internalError(asyncResp->res);
286 return;
287 }
288
289 // used for making maps out of 2 vectors
290 const std::vector<double>* keys = nullptr;
291 const std::vector<double>* values = nullptr;
292
James Feist5b4aa862018-08-16 14:07:01 -0700293 for (const auto& propertyPair : intfPair.second)
294 {
295 if (propertyPair.first == "Type" ||
296 propertyPair.first == "Class" ||
297 propertyPair.first == "Name")
298 {
299 continue;
300 }
301
302 // zones
303 if (intfPair.first == pidZoneConfigurationIface)
304 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800305 const double* ptr =
306 sdbusplus::message::variant_ns::get_if<double>(
307 &propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700308 if (ptr == nullptr)
309 {
310 BMCWEB_LOG_ERROR << "Field Illegal "
311 << propertyPair.first;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700312 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700313 return;
314 }
James Feistb7a08d02018-12-11 14:55:37 -0800315 (*config)[propertyPair.first] = *ptr;
316 }
317
318 if (intfPair.first == stepwiseConfigurationIface)
319 {
320 if (propertyPair.first == "Reading" ||
321 propertyPair.first == "Output")
322 {
323 const std::vector<double>* ptr =
324 sdbusplus::message::variant_ns::get_if<
325 std::vector<double>>(
326 &propertyPair.second);
327
328 if (ptr == nullptr)
329 {
330 BMCWEB_LOG_ERROR << "Field Illegal "
331 << propertyPair.first;
332 messages::internalError(asyncResp->res);
333 return;
334 }
335
336 if (propertyPair.first == "Reading")
337 {
338 keys = ptr;
339 }
340 else
341 {
342 values = ptr;
343 }
344 if (keys && values)
345 {
346 if (keys->size() != values->size())
347 {
348 BMCWEB_LOG_ERROR
349 << "Reading and Output size don't "
350 "match ";
351 messages::internalError(asyncResp->res);
352 return;
353 }
354 nlohmann::json& steps = (*config)["Steps"];
355 steps = nlohmann::json::array();
356 for (size_t ii = 0; ii < keys->size(); ii++)
357 {
358 steps.push_back(
359 {{"Target", (*keys)[ii]},
360 {"Output", (*values)[ii]}});
361 }
362 }
363 }
364 if (propertyPair.first == "NegativeHysteresis" ||
365 propertyPair.first == "PositiveHysteresis")
366 {
367 const double* ptr =
368 sdbusplus::message::variant_ns::get_if<
369 double>(&propertyPair.second);
370 if (ptr == nullptr)
371 {
372 BMCWEB_LOG_ERROR << "Field Illegal "
373 << propertyPair.first;
374 messages::internalError(asyncResp->res);
375 return;
376 }
377 (*config)[propertyPair.first] = *ptr;
378 }
James Feist5b4aa862018-08-16 14:07:01 -0700379 }
380
381 // pid and fans are off the same configuration
James Feistb7a08d02018-12-11 14:55:37 -0800382 if (intfPair.first == pidConfigurationIface ||
383 intfPair.first == stepwiseConfigurationIface)
James Feist5b4aa862018-08-16 14:07:01 -0700384 {
James Feist5b4aa862018-08-16 14:07:01 -0700385
386 if (propertyPair.first == "Zones")
387 {
388 const std::vector<std::string>* inputs =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800389 sdbusplus::message::variant_ns::get_if<
390 std::vector<std::string>>(
391 &propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700392
393 if (inputs == nullptr)
394 {
395 BMCWEB_LOG_ERROR
396 << "Zones Pid Field Illegal";
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800397 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700398 return;
399 }
James Feistb7a08d02018-12-11 14:55:37 -0800400 auto& data = (*config)[propertyPair.first];
James Feist5b4aa862018-08-16 14:07:01 -0700401 data = nlohmann::json::array();
402 for (std::string itemCopy : *inputs)
403 {
404 dbus::utility::escapePathForDbus(itemCopy);
405 data.push_back(
406 {{"@odata.id",
407 "/redfish/v1/Managers/bmc#/Oem/"
408 "OpenBmc/Fan/FanZones/" +
409 itemCopy}});
410 }
411 }
412 // todo(james): may never happen, but this
413 // assumes configuration data referenced in the
414 // PID config is provided by the same daemon, we
415 // could add another loop to cover all cases,
416 // but I'm okay kicking this can down the road a
417 // bit
418
419 else if (propertyPair.first == "Inputs" ||
420 propertyPair.first == "Outputs")
421 {
James Feistb7a08d02018-12-11 14:55:37 -0800422 auto& data = (*config)[propertyPair.first];
James Feist5b4aa862018-08-16 14:07:01 -0700423 const std::vector<std::string>* inputs =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800424 sdbusplus::message::variant_ns::get_if<
425 std::vector<std::string>>(
426 &propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700427
428 if (inputs == nullptr)
429 {
430 BMCWEB_LOG_ERROR << "Field Illegal "
431 << propertyPair.first;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700432 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700433 return;
434 }
435 data = *inputs;
436 } // doubles
437 else if (propertyPair.first ==
438 "FFGainCoefficient" ||
439 propertyPair.first == "FFOffCoefficient" ||
440 propertyPair.first == "ICoefficient" ||
441 propertyPair.first == "ILimitMax" ||
442 propertyPair.first == "ILimitMin" ||
443 propertyPair.first == "OutLimitMax" ||
444 propertyPair.first == "OutLimitMin" ||
445 propertyPair.first == "PCoefficient" ||
446 propertyPair.first == "SlewNeg" ||
447 propertyPair.first == "SlewPos")
448 {
449 const double* ptr =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800450 sdbusplus::message::variant_ns::get_if<
451 double>(&propertyPair.second);
James Feist5b4aa862018-08-16 14:07:01 -0700452 if (ptr == nullptr)
453 {
454 BMCWEB_LOG_ERROR << "Field Illegal "
455 << propertyPair.first;
Jason M. Billsf12894f2018-10-09 12:45:45 -0700456 messages::internalError(asyncResp->res);
James Feist5b4aa862018-08-16 14:07:01 -0700457 return;
458 }
James Feistb7a08d02018-12-11 14:55:37 -0800459 (*config)[propertyPair.first] = *ptr;
James Feist5b4aa862018-08-16 14:07:01 -0700460 }
461 }
462 }
463 }
464 }
465 },
466 connection, path, objectManagerIface, "GetManagedObjects");
467}
Jennifer Leeca537922018-08-10 10:07:30 -0700468
James Feist83ff9ab2018-08-31 10:18:24 -0700469enum class CreatePIDRet
470{
471 fail,
472 del,
473 patch
474};
475
James Feist5f2caae2018-12-12 14:08:25 -0800476static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response,
477 std::vector<nlohmann::json>& config,
478 std::vector<std::string>& zones)
479{
480
481 for (auto& odata : config)
482 {
483 std::string path;
484 if (!redfish::json_util::readJson(odata, response->res, "@odata.id",
485 path))
486 {
487 return false;
488 }
489 std::string input;
490 if (!dbus::utility::getNthStringFromPath(path, 4, input))
491 {
492 BMCWEB_LOG_ERROR << "Got invalid path " << path;
493 BMCWEB_LOG_ERROR << "Illegal Type Zones";
494 messages::propertyValueFormatError(response->res, odata.dump(),
495 "Zones");
496 return false;
497 }
498 boost::replace_all(input, "_", " ");
499 zones.emplace_back(std::move(input));
500 }
501 return true;
502}
503
James Feist83ff9ab2018-08-31 10:18:24 -0700504static CreatePIDRet createPidInterface(
505 const std::shared_ptr<AsyncResp>& response, const std::string& type,
James Feist5f2caae2018-12-12 14:08:25 -0800506 nlohmann::json&& record, const std::string& path,
James Feist83ff9ab2018-08-31 10:18:24 -0700507 const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
508 boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
509 output,
510 std::string& chassis)
511{
512
James Feist5f2caae2018-12-12 14:08:25 -0800513 // common deleter
514 if (record == nullptr)
515 {
516 std::string iface;
517 if (type == "PidControllers" || type == "FanControllers")
518 {
519 iface = pidConfigurationIface;
520 }
521 else if (type == "FanZones")
522 {
523 iface = pidZoneConfigurationIface;
524 }
525 else if (type == "StepwiseControllers")
526 {
527 iface = stepwiseConfigurationIface;
528 }
529 else
530 {
531 BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type "
532 << type;
533 messages::propertyUnknown(response->res, type);
534 return CreatePIDRet::fail;
535 }
536 // delete interface
537 crow::connections::systemBus->async_method_call(
538 [response, path](const boost::system::error_code ec) {
539 if (ec)
540 {
541 BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec;
542 messages::internalError(response->res);
543 }
544 },
545 "xyz.openbmc_project.EntityManager", path, iface, "Delete");
546 return CreatePIDRet::del;
547 }
548
James Feist83ff9ab2018-08-31 10:18:24 -0700549 if (type == "PidControllers" || type == "FanControllers")
550 {
551 if (createNewObject)
552 {
553 output["Class"] = type == "PidControllers" ? std::string("temp")
554 : std::string("fan");
555 output["Type"] = std::string("Pid");
556 }
James Feist5f2caae2018-12-12 14:08:25 -0800557
558 std::optional<std::vector<nlohmann::json>> zones;
559 std::optional<std::vector<std::string>> inputs;
560 std::optional<std::vector<std::string>> outputs;
561 std::map<std::string, std::optional<double>> doubles;
562 if (!redfish::json_util::readJson(
563 record, response->res, "Inputs", inputs, "Outputs", outputs,
564 "Zones", zones, "FFGainCoefficient",
565 doubles["FFGainCoefficient"], "FFOffCoefficient",
566 doubles["FFOffCoefficient"], "ICoefficient",
567 doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"],
568 "ILimitMin", doubles["ILimitMin"], "OutLimitMax",
569 doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"],
570 "PCoefficient", doubles["PCoefficient"], "SetPoint",
571 doubles["SetPoint"], "SlewNeg", doubles["SlewNeg"], "SlewPos",
572 doubles["SlewPos"]))
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";
886 res.jsonValue["ManagerType"] = "BMC";
Ed Tanous75176582018-12-14 08:14:34 -0800887 res.jsonValue["UUID"] = uuid;
888 res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model
Ed Tanous0f74e642018-11-12 15:17:05 -0800889
890 res.jsonValue["LogServices"] = {
891 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}};
892
893 res.jsonValue["NetworkProtocol"] = {
894 {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}};
895
896 res.jsonValue["EthernetInterfaces"] = {
897 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
898 // default oem data
899 nlohmann::json& oem = res.jsonValue["Oem"];
900 nlohmann::json& oemOpenbmc = oem["OpenBmc"];
901 oem["@odata.type"] = "#OemManager.Oem";
902 oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
903 oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
904 oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
905 oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
906 oemOpenbmc["@odata.context"] =
907 "/redfish/v1/$metadata#OemManager.OpenBmc";
908
Jennifer Leeed5befb2018-08-10 11:29:45 -0700909 // Update Actions object.
Ed Tanous0f74e642018-11-12 15:17:05 -0800910 nlohmann::json& manager_reset =
911 res.jsonValue["Actions"]["#Manager.Reset"];
Jennifer Leeed5befb2018-08-10 11:29:45 -0700912 manager_reset["target"] =
913 "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
914 manager_reset["ResetType@Redfish.AllowableValues"] = {
915 "GracefulRestart"};
Jennifer Leeca537922018-08-10 10:07:30 -0700916
Ed Tanous0f74e642018-11-12 15:17:05 -0800917 res.jsonValue["DateTime"] = getDateTime();
Jennifer Leeed5befb2018-08-10 11:29:45 -0700918 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
James Feist5b4aa862018-08-16 14:07:01 -0700919
Jennifer Leeca537922018-08-10 10:07:30 -0700920 crow::connections::systemBus->async_method_call(
921 [asyncResp](const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -0700922 const dbus::utility::ManagedObjectType& resp) {
Jennifer Leeca537922018-08-10 10:07:30 -0700923 if (ec)
924 {
925 BMCWEB_LOG_ERROR << "Error while getting Software Version";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700926 messages::internalError(asyncResp->res);
Jennifer Leeca537922018-08-10 10:07:30 -0700927 return;
928 }
929
James Feist5b4aa862018-08-16 14:07:01 -0700930 for (auto& objpath : resp)
Jennifer Leeca537922018-08-10 10:07:30 -0700931 {
James Feist5b4aa862018-08-16 14:07:01 -0700932 for (auto& interface : objpath.second)
Jennifer Leeca537922018-08-10 10:07:30 -0700933 {
James Feist5f2caae2018-12-12 14:08:25 -0800934 // If interface is
935 // xyz.openbmc_project.Software.Version, this is
936 // what we're looking for.
Jennifer Leeca537922018-08-10 10:07:30 -0700937 if (interface.first ==
938 "xyz.openbmc_project.Software.Version")
939 {
940 // Cut out everyting until last "/", ...
James Feist5b4aa862018-08-16 14:07:01 -0700941 const std::string& iface_id = objpath.first;
942 for (auto& property : interface.second)
Jennifer Leeca537922018-08-10 10:07:30 -0700943 {
944 if (property.first == "Version")
945 {
James Feist5b4aa862018-08-16 14:07:01 -0700946 const std::string* value =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800947 sdbusplus::message::variant_ns::get_if<
948 std::string>(&property.second);
Jennifer Leeca537922018-08-10 10:07:30 -0700949 if (value == nullptr)
950 {
951 continue;
952 }
953 asyncResp->res
954 .jsonValue["FirmwareVersion"] = *value;
955 }
956 }
957 }
958 }
959 }
960 },
961 "xyz.openbmc_project.Software.BMC.Updater",
962 "/xyz/openbmc_project/software",
963 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist5b4aa862018-08-16 14:07:01 -0700964 getPidValues(asyncResp);
965 }
James Feist5f2caae2018-12-12 14:08:25 -0800966 void setPidValues(std::shared_ptr<AsyncResp> response, nlohmann::json& data)
James Feist83ff9ab2018-08-31 10:18:24 -0700967 {
James Feist5f2caae2018-12-12 14:08:25 -0800968
James Feist83ff9ab2018-08-31 10:18:24 -0700969 // todo(james): might make sense to do a mapper call here if this
970 // interface gets more traction
971 crow::connections::systemBus->async_method_call(
972 [response,
973 data](const boost::system::error_code ec,
974 const dbus::utility::ManagedObjectType& managedObj) {
975 if (ec)
976 {
977 BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
Jason M. Bills35a62c72018-10-09 12:45:45 -0700978 messages::internalError(response->res);
James Feist83ff9ab2018-08-31 10:18:24 -0700979 return;
980 }
James Feist5f2caae2018-12-12 14:08:25 -0800981
982 // todo(james) mutable doesn't work with asio bindings
983 nlohmann::json jsonData = data;
984
985 std::optional<nlohmann::json> pidControllers;
986 std::optional<nlohmann::json> fanControllers;
987 std::optional<nlohmann::json> fanZones;
988 std::optional<nlohmann::json> stepwiseControllers;
989 if (!redfish::json_util::readJson(
990 jsonData, response->res, "PidControllers",
991 pidControllers, "FanControllers", fanControllers,
992 "FanZones", fanZones, "StepwiseControllers",
993 stepwiseControllers))
James Feist83ff9ab2018-08-31 10:18:24 -0700994 {
James Feist5f2caae2018-12-12 14:08:25 -0800995 BMCWEB_LOG_ERROR << "Line:" << __LINE__
996 << ", Illegal Property "
997 << jsonData.dump();
998 return;
999 }
1000 std::array<
1001 std::pair<const char*, std::optional<nlohmann::json>*>, 4>
1002 sections = {
1003 std::make_pair("PidControllers", &pidControllers),
1004 std::make_pair("FanControllers", &fanControllers),
1005 std::make_pair("FanZones", &fanZones),
1006 std::make_pair("StepwiseControllers",
1007 &stepwiseControllers)};
1008
1009 for (auto& containerPair : sections)
1010 {
1011 auto& container = *(containerPair.second);
1012 if (!container)
James Feist83ff9ab2018-08-31 10:18:24 -07001013 {
James Feist5f2caae2018-12-12 14:08:25 -08001014 continue;
James Feist83ff9ab2018-08-31 10:18:24 -07001015 }
James Feist5f2caae2018-12-12 14:08:25 -08001016 const char* type = containerPair.first;
1017
1018 for (auto& record : container->items())
James Feist83ff9ab2018-08-31 10:18:24 -07001019 {
James Feist5f2caae2018-12-12 14:08:25 -08001020 const auto& name = record.key();
James Feist83ff9ab2018-08-31 10:18:24 -07001021 auto pathItr =
1022 std::find_if(managedObj.begin(), managedObj.end(),
1023 [&name](const auto& obj) {
1024 return boost::algorithm::ends_with(
1025 obj.first.str, name);
1026 });
1027 boost::container::flat_map<
1028 std::string, dbus::utility::DbusVariantType>
1029 output;
1030
1031 output.reserve(16); // The pid interface length
1032
1033 // determines if we're patching entity-manager or
1034 // creating a new object
1035 bool createNewObject = (pathItr == managedObj.end());
James Feist5f2caae2018-12-12 14:08:25 -08001036 std::string iface;
1037 if (type == "PidControllers" ||
1038 type == "FanControllers")
James Feist83ff9ab2018-08-31 10:18:24 -07001039 {
James Feist5f2caae2018-12-12 14:08:25 -08001040 iface = pidConfigurationIface;
James Feist83ff9ab2018-08-31 10:18:24 -07001041 if (!createNewObject &&
1042 pathItr->second.find(pidConfigurationIface) ==
1043 pathItr->second.end())
1044 {
1045 createNewObject = true;
1046 }
1047 }
James Feist5f2caae2018-12-12 14:08:25 -08001048 else if (type == "FanZones")
James Feist83ff9ab2018-08-31 10:18:24 -07001049 {
James Feist5f2caae2018-12-12 14:08:25 -08001050 iface = pidZoneConfigurationIface;
1051 if (!createNewObject &&
1052 pathItr->second.find(
1053 pidZoneConfigurationIface) ==
1054 pathItr->second.end())
1055 {
1056
1057 createNewObject = true;
1058 }
1059 }
1060 else if (type == "StepwiseControllers")
1061 {
1062 iface = stepwiseConfigurationIface;
1063 if (!createNewObject &&
1064 pathItr->second.find(
1065 stepwiseConfigurationIface) ==
1066 pathItr->second.end())
1067 {
1068 createNewObject = true;
1069 }
James Feist83ff9ab2018-08-31 10:18:24 -07001070 }
1071 output["Name"] =
1072 boost::replace_all_copy(name, "_", " ");
1073
1074 std::string chassis;
1075 CreatePIDRet ret = createPidInterface(
James Feist5f2caae2018-12-12 14:08:25 -08001076 response, type, std::move(record.value()),
James Feist83ff9ab2018-08-31 10:18:24 -07001077 pathItr->first.str, managedObj, createNewObject,
1078 output, chassis);
1079 if (ret == CreatePIDRet::fail)
1080 {
1081 return;
1082 }
1083 else if (ret == CreatePIDRet::del)
1084 {
1085 continue;
1086 }
1087
1088 if (!createNewObject)
1089 {
1090 for (const auto& property : output)
1091 {
James Feist83ff9ab2018-08-31 10:18:24 -07001092 crow::connections::systemBus->async_method_call(
1093 [response,
1094 propertyName{std::string(property.first)}](
1095 const boost::system::error_code ec) {
1096 if (ec)
1097 {
1098 BMCWEB_LOG_ERROR
1099 << "Error patching "
1100 << propertyName << ": " << ec;
Jason M. Bills35a62c72018-10-09 12:45:45 -07001101 messages::internalError(
1102 response->res);
James Feist83ff9ab2018-08-31 10:18:24 -07001103 }
1104 },
1105 "xyz.openbmc_project.EntityManager",
1106 pathItr->first.str,
1107 "org.freedesktop.DBus.Properties", "Set",
James Feist5f2caae2018-12-12 14:08:25 -08001108 iface, property.first, property.second);
James Feist83ff9ab2018-08-31 10:18:24 -07001109 }
1110 }
1111 else
1112 {
1113 if (chassis.empty())
1114 {
1115 BMCWEB_LOG_ERROR
1116 << "Failed to get chassis from config";
Jason M. Bills35a62c72018-10-09 12:45:45 -07001117 messages::invalidObject(response->res, name);
James Feist83ff9ab2018-08-31 10:18:24 -07001118 return;
1119 }
1120
1121 bool foundChassis = false;
1122 for (const auto& obj : managedObj)
1123 {
1124 if (boost::algorithm::ends_with(obj.first.str,
1125 chassis))
1126 {
1127 chassis = obj.first.str;
1128 foundChassis = true;
1129 break;
1130 }
1131 }
1132 if (!foundChassis)
1133 {
1134 BMCWEB_LOG_ERROR
1135 << "Failed to find chassis on dbus";
Jason M. Bills35a62c72018-10-09 12:45:45 -07001136 messages::resourceMissingAtURI(
1137 response->res,
1138 "/redfish/v1/Chassis/" + chassis);
James Feist83ff9ab2018-08-31 10:18:24 -07001139 return;
1140 }
1141
1142 crow::connections::systemBus->async_method_call(
1143 [response](const boost::system::error_code ec) {
1144 if (ec)
1145 {
1146 BMCWEB_LOG_ERROR
1147 << "Error Adding Pid Object " << ec;
Jason M. Bills35a62c72018-10-09 12:45:45 -07001148 messages::internalError(response->res);
James Feist83ff9ab2018-08-31 10:18:24 -07001149 }
1150 },
1151 "xyz.openbmc_project.EntityManager", chassis,
1152 "xyz.openbmc_project.AddObject", "AddObject",
1153 output);
1154 }
1155 }
1156 }
1157 },
1158 "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
1159 "GetManagedObjects");
1160 }
James Feist5b4aa862018-08-16 14:07:01 -07001161
1162 void doPatch(crow::Response& res, const crow::Request& req,
1163 const std::vector<std::string>& params) override
1164 {
Ed Tanous0627a2c2018-11-29 17:09:23 -08001165 std::optional<nlohmann::json> oem;
1166
1167 if (!json_util::readJson(req, res, "Oem", oem))
James Feist83ff9ab2018-08-31 10:18:24 -07001168 {
1169 return;
1170 }
Ed Tanous0627a2c2018-11-29 17:09:23 -08001171
James Feist83ff9ab2018-08-31 10:18:24 -07001172 std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001173
1174 if (oem)
James Feist83ff9ab2018-08-31 10:18:24 -07001175 {
Ed Tanous0627a2c2018-11-29 17:09:23 -08001176 for (const auto& oemLevel : oem->items())
James Feist83ff9ab2018-08-31 10:18:24 -07001177 {
James Feist5f2caae2018-12-12 14:08:25 -08001178 std::optional<nlohmann::json> openbmc;
1179 if (!redfish::json_util::readJson(*oem, res, "OpenBmc",
1180 openbmc))
James Feist83ff9ab2018-08-31 10:18:24 -07001181 {
James Feist5f2caae2018-12-12 14:08:25 -08001182 BMCWEB_LOG_ERROR << "Line:" << __LINE__
1183 << ", Illegal Property " << oem->dump();
1184 return;
1185 }
1186 if (openbmc)
1187 {
1188 std::optional<nlohmann::json> fan;
1189 if (!redfish::json_util::readJson(*openbmc, res, "Fan",
1190 fan))
James Feist83ff9ab2018-08-31 10:18:24 -07001191 {
James Feist5f2caae2018-12-12 14:08:25 -08001192 BMCWEB_LOG_ERROR << "Line:" << __LINE__
1193 << ", Illegal Property "
1194 << openbmc->dump();
James Feist83ff9ab2018-08-31 10:18:24 -07001195 return;
1196 }
James Feist5f2caae2018-12-12 14:08:25 -08001197 if (fan)
James Feist83ff9ab2018-08-31 10:18:24 -07001198 {
James Feist5f2caae2018-12-12 14:08:25 -08001199 setPidValues(response, *fan);
James Feist83ff9ab2018-08-31 10:18:24 -07001200 }
1201 }
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