1 /*
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 "bmcweb_config.h"
19
20 #include "app.hpp"
21 #include "dbus_singleton.hpp"
22 #include "dbus_utility.hpp"
23 #include "generated/enums/action_info.hpp"
24 #include "generated/enums/computer_system.hpp"
25 #include "generated/enums/open_bmc_computer_system.hpp"
26 #include "generated/enums/resource.hpp"
27 #include "hypervisor_system.hpp"
28 #include "led.hpp"
29 #include "query.hpp"
30 #include "redfish_util.hpp"
31 #include "registries/privilege_registry.hpp"
32 #include "utils/dbus_utils.hpp"
33 #include "utils/json_utils.hpp"
34 #include "utils/pcie_util.hpp"
35 #include "utils/sw_utils.hpp"
36 #include "utils/time_utils.hpp"
37
38 #include <boost/asio/error.hpp>
39 #include <boost/container/flat_map.hpp>
40 #include <boost/system/error_code.hpp>
41 #include <boost/system/linux_error.hpp>
42 #include <boost/url/format.hpp>
43 #include <sdbusplus/asio/property.hpp>
44 #include <sdbusplus/message.hpp>
45 #include <sdbusplus/unpack_properties.hpp>
46
47 #include <array>
48 #include <memory>
49 #include <string>
50 #include <string_view>
51 #include <utility>
52 #include <variant>
53 #include <vector>
54
55 namespace redfish
56 {
57
58 const static std::array<std::pair<std::string_view, std::string_view>, 2>
59 protocolToDBusForSystems{
60 {{"SSH", "obmc-console-ssh"}, {"IPMI", "phosphor-ipmi-net"}}};
61
62 /**
63 * @brief Updates the Functional State of DIMMs
64 *
65 * @param[in] asyncResp Shared pointer for completing asynchronous calls
66 * @param[in] dimmState Dimm's Functional state, true/false
67 *
68 * @return None.
69 */
updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,bool isDimmFunctional)70 inline void updateDimmProperties(
71 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool isDimmFunctional)
72 {
73 BMCWEB_LOG_DEBUG("Dimm Functional: {}", isDimmFunctional);
74
75 // Set it as Enabled if at least one DIMM is functional
76 // Update STATE only if previous State was DISABLED and current Dimm is
77 // ENABLED.
78 const nlohmann::json& prevMemSummary =
79 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"];
80 if (prevMemSummary == "Disabled")
81 {
82 if (isDimmFunctional)
83 {
84 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
85 "Enabled";
86 }
87 }
88 }
89
90 /*
91 * @brief Update "ProcessorSummary" "Status" "State" based on
92 * CPU Functional State
93 *
94 * @param[in] asyncResp Shared pointer for completing asynchronous calls
95 * @param[in] cpuFunctionalState is CPU functional true/false
96 *
97 * @return None.
98 */
modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,bool isCpuFunctional)99 inline void modifyCpuFunctionalState(
100 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool isCpuFunctional)
101 {
102 BMCWEB_LOG_DEBUG("Cpu Functional: {}", isCpuFunctional);
103
104 const nlohmann::json& prevProcState =
105 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
106
107 // Set it as Enabled if at least one CPU is functional
108 // Update STATE only if previous State was Non_Functional and current CPU is
109 // Functional.
110 if (prevProcState == "Disabled")
111 {
112 if (isCpuFunctional)
113 {
114 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
115 "Enabled";
116 }
117 }
118 }
119
120 /*
121 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
122 *
123 * @param[in] asyncResp Shared pointer for completing asynchronous calls
124 * @param[in] cpuPresenceState CPU present or not
125 *
126 * @return None.
127 */
modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,bool isCpuPresent)128 inline void modifyCpuPresenceState(
129 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool isCpuPresent)
130 {
131 BMCWEB_LOG_DEBUG("Cpu Present: {}", isCpuPresent);
132
133 if (isCpuPresent)
134 {
135 nlohmann::json& procCount =
136 asyncResp->res.jsonValue["ProcessorSummary"]["Count"];
137 auto* procCountPtr =
138 procCount.get_ptr<nlohmann::json::number_integer_t*>();
139 if (procCountPtr != nullptr)
140 {
141 // shouldn't be possible to be nullptr
142 *procCountPtr += 1;
143 }
144 }
145 }
146
getProcessorProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::vector<std::pair<std::string,dbus::utility::DbusVariantType>> & properties)147 inline void getProcessorProperties(
148 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
149 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
150 properties)
151 {
152 BMCWEB_LOG_DEBUG("Got {} Cpu properties.", properties.size());
153
154 // TODO: Get Model
155
156 const uint16_t* coreCount = nullptr;
157
158 const bool success = sdbusplus::unpackPropertiesNoThrow(
159 dbus_utils::UnpackErrorPrinter(), properties, "CoreCount", coreCount);
160
161 if (!success)
162 {
163 messages::internalError(asyncResp->res);
164 return;
165 }
166
167 if (coreCount != nullptr)
168 {
169 nlohmann::json& coreCountJson =
170 asyncResp->res.jsonValue["ProcessorSummary"]["CoreCount"];
171 uint64_t* coreCountJsonPtr = coreCountJson.get_ptr<uint64_t*>();
172
173 if (coreCountJsonPtr == nullptr)
174 {
175 coreCountJson = *coreCount;
176 }
177 else
178 {
179 *coreCountJsonPtr += *coreCount;
180 }
181 }
182 }
183
184 /*
185 * @brief Get ProcessorSummary fields
186 *
187 * @param[in] asyncResp Shared pointer for completing asynchronous calls
188 * @param[in] service dbus service for Cpu Information
189 * @param[in] path dbus path for Cpu
190 *
191 * @return None.
192 */
193 inline void
getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)194 getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
195 const std::string& service, const std::string& path)
196 {
197 auto getCpuPresenceState = [asyncResp](const boost::system::error_code& ec3,
198 const bool cpuPresenceCheck) {
199 if (ec3)
200 {
201 BMCWEB_LOG_ERROR("DBUS response error {}", ec3);
202 return;
203 }
204 modifyCpuPresenceState(asyncResp, cpuPresenceCheck);
205 };
206
207 // Get the Presence of CPU
208 sdbusplus::asio::getProperty<bool>(
209 *crow::connections::systemBus, service, path,
210 "xyz.openbmc_project.Inventory.Item", "Present",
211 std::move(getCpuPresenceState));
212
213 sdbusplus::asio::getAllProperties(
214 *crow::connections::systemBus, service, path,
215 "xyz.openbmc_project.Inventory.Item.Cpu",
216 [asyncResp, service,
217 path](const boost::system::error_code& ec2,
218 const dbus::utility::DBusPropertiesMap& properties) {
219 if (ec2)
220 {
221 BMCWEB_LOG_ERROR("DBUS response error {}", ec2);
222 messages::internalError(asyncResp->res);
223 return;
224 }
225 getProcessorProperties(asyncResp, properties);
226 });
227 }
228
229 /*
230 * @brief processMemoryProperties fields
231 *
232 * @param[in] asyncResp Shared pointer for completing asynchronous calls
233 * @param[in] DBUS properties for memory
234 *
235 * @return None.
236 */
237 inline void
processMemoryProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & properties)238 processMemoryProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
239 const dbus::utility::DBusPropertiesMap& properties)
240 {
241 BMCWEB_LOG_DEBUG("Got {} Dimm properties.", properties.size());
242
243 if (properties.empty())
244 {
245 return;
246 }
247
248 const size_t* memorySizeInKB = nullptr;
249
250 const bool success = sdbusplus::unpackPropertiesNoThrow(
251 dbus_utils::UnpackErrorPrinter(), properties, "MemorySizeInKB",
252 memorySizeInKB);
253
254 if (!success)
255 {
256 messages::internalError(asyncResp->res);
257 return;
258 }
259
260 if (memorySizeInKB != nullptr)
261 {
262 nlohmann::json& totalMemory =
263 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"];
264 const double* preValue = totalMemory.get_ptr<const double*>();
265 if (preValue == nullptr)
266 {
267 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
268 static_cast<double>(*memorySizeInKB) / (1024 * 1024);
269 }
270 else
271 {
272 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
273 static_cast<double>(*memorySizeInKB) / (1024 * 1024) +
274 *preValue;
275 }
276 }
277 }
278
279 /*
280 * @brief Get getMemorySummary fields
281 *
282 * @param[in] asyncResp Shared pointer for completing asynchronous calls
283 * @param[in] service dbus service for memory Information
284 * @param[in] path dbus path for memory
285 *
286 * @return None.
287 */
288 inline void
getMemorySummary(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & service,const std::string & path)289 getMemorySummary(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
290 const std::string& service, const std::string& path)
291 {
292 sdbusplus::asio::getAllProperties(
293 *crow::connections::systemBus, service, path,
294 "xyz.openbmc_project.Inventory.Item.Dimm",
295 [asyncResp, service,
296 path](const boost::system::error_code& ec2,
297 const dbus::utility::DBusPropertiesMap& properties) {
298 if (ec2)
299 {
300 BMCWEB_LOG_ERROR("DBUS response error {}", ec2);
301 messages::internalError(asyncResp->res);
302 return;
303 }
304 processMemoryProperties(asyncResp, properties);
305 });
306 }
307
afterGetUUID(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & properties)308 inline void afterGetUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
309 const boost::system::error_code& ec,
310 const dbus::utility::DBusPropertiesMap& properties)
311 {
312 if (ec)
313 {
314 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
315 messages::internalError(asyncResp->res);
316 return;
317 }
318 BMCWEB_LOG_DEBUG("Got {} UUID properties.", properties.size());
319
320 const std::string* uUID = nullptr;
321
322 const bool success = sdbusplus::unpackPropertiesNoThrow(
323 dbus_utils::UnpackErrorPrinter(), properties, "UUID", uUID);
324
325 if (!success)
326 {
327 messages::internalError(asyncResp->res);
328 return;
329 }
330
331 if (uUID != nullptr)
332 {
333 std::string valueStr = *uUID;
334 if (valueStr.size() == 32)
335 {
336 valueStr.insert(8, 1, '-');
337 valueStr.insert(13, 1, '-');
338 valueStr.insert(18, 1, '-');
339 valueStr.insert(23, 1, '-');
340 }
341 BMCWEB_LOG_DEBUG("UUID = {}", valueStr);
342 asyncResp->res.jsonValue["UUID"] = valueStr;
343 }
344 }
345
346 inline void
afterGetInventory(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & propertiesList)347 afterGetInventory(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
348 const boost::system::error_code& ec,
349 const dbus::utility::DBusPropertiesMap& propertiesList)
350 {
351 if (ec)
352 {
353 // doesn't have to include this
354 // interface
355 return;
356 }
357 BMCWEB_LOG_DEBUG("Got {} properties for system", propertiesList.size());
358
359 const std::string* partNumber = nullptr;
360 const std::string* serialNumber = nullptr;
361 const std::string* manufacturer = nullptr;
362 const std::string* model = nullptr;
363 const std::string* subModel = nullptr;
364
365 const bool success = sdbusplus::unpackPropertiesNoThrow(
366 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
367 partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
368 "Model", model, "SubModel", subModel);
369
370 if (!success)
371 {
372 messages::internalError(asyncResp->res);
373 return;
374 }
375
376 if (partNumber != nullptr)
377 {
378 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
379 }
380
381 if (serialNumber != nullptr)
382 {
383 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
384 }
385
386 if (manufacturer != nullptr)
387 {
388 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
389 }
390
391 if (model != nullptr)
392 {
393 asyncResp->res.jsonValue["Model"] = *model;
394 }
395
396 if (subModel != nullptr)
397 {
398 asyncResp->res.jsonValue["SubModel"] = *subModel;
399 }
400
401 // Grab the bios version
402 sw_util::populateSoftwareInformation(asyncResp, sw_util::biosPurpose,
403 "BiosVersion", false);
404 }
405
afterGetAssetTag(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::string & value)406 inline void afterGetAssetTag(
407 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
408 const boost::system::error_code& ec, const std::string& value)
409 {
410 if (ec)
411 {
412 // doesn't have to include this
413 // interface
414 return;
415 }
416
417 asyncResp->res.jsonValue["AssetTag"] = value;
418 }
419
afterSystemGetSubTree(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)420 inline void afterSystemGetSubTree(
421 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
422 const boost::system::error_code& ec,
423 const dbus::utility::MapperGetSubTreeResponse& subtree)
424 {
425 if (ec)
426 {
427 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
428 messages::internalError(asyncResp->res);
429 return;
430 }
431 // Iterate over all retrieved ObjectPaths.
432 for (const std::pair<
433 std::string,
434 std::vector<std::pair<std::string, std::vector<std::string>>>>&
435 object : subtree)
436 {
437 const std::string& path = object.first;
438 BMCWEB_LOG_DEBUG("Got path: {}", path);
439 const std::vector<std::pair<std::string, std::vector<std::string>>>&
440 connectionNames = object.second;
441 if (connectionNames.empty())
442 {
443 continue;
444 }
445
446 // This is not system, so check if it's cpu, dimm, UUID or
447 // BiosVer
448 for (const auto& connection : connectionNames)
449 {
450 for (const auto& interfaceName : connection.second)
451 {
452 if (interfaceName == "xyz.openbmc_project.Inventory.Item.Dimm")
453 {
454 BMCWEB_LOG_DEBUG("Found Dimm, now get its properties.");
455
456 getMemorySummary(asyncResp, connection.first, path);
457 }
458 else if (interfaceName ==
459 "xyz.openbmc_project.Inventory.Item.Cpu")
460 {
461 BMCWEB_LOG_DEBUG("Found Cpu, now get its properties.");
462
463 getProcessorSummary(asyncResp, connection.first, path);
464 }
465 else if (interfaceName == "xyz.openbmc_project.Common.UUID")
466 {
467 BMCWEB_LOG_DEBUG("Found UUID, now get its properties.");
468
469 sdbusplus::asio::getAllProperties(
470 *crow::connections::systemBus, connection.first, path,
471 "xyz.openbmc_project.Common.UUID",
472 [asyncResp](const boost::system::error_code& ec3,
473 const dbus::utility::DBusPropertiesMap&
474 properties) {
475 afterGetUUID(asyncResp, ec3, properties);
476 });
477 }
478 else if (interfaceName ==
479 "xyz.openbmc_project.Inventory.Item.System")
480 {
481 sdbusplus::asio::getAllProperties(
482 *crow::connections::systemBus, connection.first, path,
483 "xyz.openbmc_project.Inventory.Decorator.Asset",
484 [asyncResp](const boost::system::error_code& ec3,
485 const dbus::utility::DBusPropertiesMap&
486 properties) {
487 afterGetInventory(asyncResp, ec3, properties);
488 });
489
490 sdbusplus::asio::getProperty<std::string>(
491 *crow::connections::systemBus, connection.first, path,
492 "xyz.openbmc_project.Inventory.Decorator."
493 "AssetTag",
494 "AssetTag",
495 std::bind_front(afterGetAssetTag, asyncResp));
496 }
497 }
498 }
499 }
500 }
501
502 /*
503 * @brief Retrieves computer system properties over dbus
504 *
505 * @param[in] asyncResp Shared pointer for completing asynchronous calls
506 *
507 * @return None.
508 */
509 inline void
getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)510 getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
511 {
512 BMCWEB_LOG_DEBUG("Get available system components.");
513 constexpr std::array<std::string_view, 5> interfaces = {
514 "xyz.openbmc_project.Inventory.Decorator.Asset",
515 "xyz.openbmc_project.Inventory.Item.Cpu",
516 "xyz.openbmc_project.Inventory.Item.Dimm",
517 "xyz.openbmc_project.Inventory.Item.System",
518 "xyz.openbmc_project.Common.UUID",
519 };
520 dbus::utility::getSubTree(
521 "/xyz/openbmc_project/inventory", 0, interfaces,
522 std::bind_front(afterSystemGetSubTree, asyncResp));
523 }
524
525 /**
526 * @brief Retrieves host state properties over dbus
527 *
528 * @param[in] asyncResp Shared pointer for completing asynchronous calls.
529 *
530 * @return None.
531 */
getHostState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)532 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
533 {
534 BMCWEB_LOG_DEBUG("Get host information.");
535 sdbusplus::asio::getProperty<std::string>(
536 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
537 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host",
538 "CurrentHostState",
539 [asyncResp](const boost::system::error_code& ec,
540 const std::string& hostState) {
541 if (ec)
542 {
543 if (ec == boost::system::errc::host_unreachable)
544 {
545 // Service not available, no error, just don't return
546 // host state info
547 BMCWEB_LOG_DEBUG("Service not available {}", ec);
548 return;
549 }
550 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
551 messages::internalError(asyncResp->res);
552 return;
553 }
554
555 BMCWEB_LOG_DEBUG("Host state: {}", hostState);
556 // Verify Host State
557 if (hostState == "xyz.openbmc_project.State.Host.HostState.Running")
558 {
559 asyncResp->res.jsonValue["PowerState"] =
560 resource::PowerState::On;
561 asyncResp->res.jsonValue["Status"]["State"] =
562 resource::State::Enabled;
563 }
564 else if (hostState ==
565 "xyz.openbmc_project.State.Host.HostState.Quiesced")
566 {
567 asyncResp->res.jsonValue["PowerState"] =
568 resource::PowerState::On;
569 asyncResp->res.jsonValue["Status"]["State"] =
570 resource::State::Quiesced;
571 }
572 else if (hostState ==
573 "xyz.openbmc_project.State.Host.HostState.DiagnosticMode")
574 {
575 asyncResp->res.jsonValue["PowerState"] =
576 resource::PowerState::On;
577 asyncResp->res.jsonValue["Status"]["State"] =
578 resource::State::InTest;
579 }
580 else if (
581 hostState ==
582 "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning")
583 {
584 asyncResp->res.jsonValue["PowerState"] =
585 resource::PowerState::PoweringOn;
586 asyncResp->res.jsonValue["Status"]["State"] =
587 resource::State::Starting;
588 }
589 else if (
590 hostState ==
591 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff")
592 {
593 asyncResp->res.jsonValue["PowerState"] =
594 resource::PowerState::PoweringOff;
595 asyncResp->res.jsonValue["Status"]["State"] =
596 resource::State::Disabled;
597 }
598 else
599 {
600 asyncResp->res.jsonValue["PowerState"] =
601 resource::PowerState::Off;
602 asyncResp->res.jsonValue["Status"]["State"] =
603 resource::State::Disabled;
604 }
605 });
606 }
607
608 /**
609 * @brief Translates boot source DBUS property value to redfish.
610 *
611 * @param[in] dbusSource The boot source in DBUS speak.
612 *
613 * @return Returns as a string, the boot source in Redfish terms. If translation
614 * cannot be done, returns an empty string.
615 */
dbusToRfBootSource(const std::string & dbusSource)616 inline std::string dbusToRfBootSource(const std::string& dbusSource)
617 {
618 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
619 {
620 return "None";
621 }
622 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
623 {
624 return "Hdd";
625 }
626 if (dbusSource ==
627 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
628 {
629 return "Cd";
630 }
631 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
632 {
633 return "Pxe";
634 }
635 if (dbusSource ==
636 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
637 {
638 return "Usb";
639 }
640 return "";
641 }
642
643 /**
644 * @brief Translates boot type DBUS property value to redfish.
645 *
646 * @param[in] dbusType The boot type in DBUS speak.
647 *
648 * @return Returns as a string, the boot type in Redfish terms. If translation
649 * cannot be done, returns an empty string.
650 */
dbusToRfBootType(const std::string & dbusType)651 inline std::string dbusToRfBootType(const std::string& dbusType)
652 {
653 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy")
654 {
655 return "Legacy";
656 }
657 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI")
658 {
659 return "UEFI";
660 }
661 return "";
662 }
663
664 /**
665 * @brief Translates boot mode DBUS property value to redfish.
666 *
667 * @param[in] dbusMode The boot mode in DBUS speak.
668 *
669 * @return Returns as a string, the boot mode in Redfish terms. If translation
670 * cannot be done, returns an empty string.
671 */
dbusToRfBootMode(const std::string & dbusMode)672 inline std::string dbusToRfBootMode(const std::string& dbusMode)
673 {
674 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
675 {
676 return "None";
677 }
678 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
679 {
680 return "Diags";
681 }
682 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
683 {
684 return "BiosSetup";
685 }
686 return "";
687 }
688
689 /**
690 * @brief Translates boot progress DBUS property value to redfish.
691 *
692 * @param[in] dbusBootProgress The boot progress in DBUS speak.
693 *
694 * @return Returns as a string, the boot progress in Redfish terms. If
695 * translation cannot be done, returns "None".
696 */
dbusToRfBootProgress(const std::string & dbusBootProgress)697 inline std::string dbusToRfBootProgress(const std::string& dbusBootProgress)
698 {
699 // Now convert the D-Bus BootProgress to the appropriate Redfish
700 // enum
701 std::string rfBpLastState = "None";
702 if (dbusBootProgress == "xyz.openbmc_project.State.Boot.Progress."
703 "ProgressStages.Unspecified")
704 {
705 rfBpLastState = "None";
706 }
707 else if (dbusBootProgress ==
708 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
709 "PrimaryProcInit")
710 {
711 rfBpLastState = "PrimaryProcessorInitializationStarted";
712 }
713 else if (dbusBootProgress ==
714 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
715 "BusInit")
716 {
717 rfBpLastState = "BusInitializationStarted";
718 }
719 else if (dbusBootProgress ==
720 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
721 "MemoryInit")
722 {
723 rfBpLastState = "MemoryInitializationStarted";
724 }
725 else if (dbusBootProgress ==
726 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
727 "SecondaryProcInit")
728 {
729 rfBpLastState = "SecondaryProcessorInitializationStarted";
730 }
731 else if (dbusBootProgress ==
732 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
733 "PCIInit")
734 {
735 rfBpLastState = "PCIResourceConfigStarted";
736 }
737 else if (dbusBootProgress ==
738 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
739 "SystemSetup")
740 {
741 rfBpLastState = "SetupEntered";
742 }
743 else if (dbusBootProgress ==
744 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
745 "SystemInitComplete")
746 {
747 rfBpLastState = "SystemHardwareInitializationComplete";
748 }
749 else if (dbusBootProgress ==
750 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
751 "OSStart")
752 {
753 rfBpLastState = "OSBootStarted";
754 }
755 else if (dbusBootProgress ==
756 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
757 "OSRunning")
758 {
759 rfBpLastState = "OSRunning";
760 }
761 else
762 {
763 BMCWEB_LOG_DEBUG("Unsupported D-Bus BootProgress {}", dbusBootProgress);
764 // Just return the default
765 }
766 return rfBpLastState;
767 }
768
769 /**
770 * @brief Translates boot source from Redfish to the DBus boot paths.
771 *
772 * @param[in] rfSource The boot source in Redfish.
773 * @param[out] bootSource The DBus source
774 * @param[out] bootMode the DBus boot mode
775 *
776 * @return Integer error code.
777 */
assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & rfSource,std::string & bootSource,std::string & bootMode)778 inline int assignBootParameters(
779 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
780 const std::string& rfSource, std::string& bootSource, std::string& bootMode)
781 {
782 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
783 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
784
785 if (rfSource == "None")
786 {
787 return 0;
788 }
789 if (rfSource == "Pxe")
790 {
791 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
792 }
793 else if (rfSource == "Hdd")
794 {
795 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
796 }
797 else if (rfSource == "Diags")
798 {
799 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
800 }
801 else if (rfSource == "Cd")
802 {
803 bootSource =
804 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
805 }
806 else if (rfSource == "BiosSetup")
807 {
808 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
809 }
810 else if (rfSource == "Usb")
811 {
812 bootSource =
813 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
814 }
815 else
816 {
817 BMCWEB_LOG_DEBUG(
818 "Invalid property value for BootSourceOverrideTarget: {}",
819 bootSource);
820 messages::propertyValueNotInList(asyncResp->res, rfSource,
821 "BootSourceTargetOverride");
822 return -1;
823 }
824 return 0;
825 }
826
827 /**
828 * @brief Retrieves boot progress of the system
829 *
830 * @param[in] asyncResp Shared pointer for generating response message.
831 *
832 * @return None.
833 */
getBootProgress(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)834 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
835 {
836 sdbusplus::asio::getProperty<std::string>(
837 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
838 "/xyz/openbmc_project/state/host0",
839 "xyz.openbmc_project.State.Boot.Progress", "BootProgress",
840 [asyncResp](const boost::system::error_code& ec,
841 const std::string& bootProgressStr) {
842 if (ec)
843 {
844 // BootProgress is an optional object so just do nothing if
845 // not found
846 return;
847 }
848
849 BMCWEB_LOG_DEBUG("Boot Progress: {}", bootProgressStr);
850
851 asyncResp->res.jsonValue["BootProgress"]["LastState"] =
852 dbusToRfBootProgress(bootProgressStr);
853 });
854 }
855
856 /**
857 * @brief Retrieves boot progress Last Update of the system
858 *
859 * @param[in] asyncResp Shared pointer for generating response message.
860 *
861 * @return None.
862 */
getBootProgressLastStateTime(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)863 inline void getBootProgressLastStateTime(
864 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
865 {
866 sdbusplus::asio::getProperty<uint64_t>(
867 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
868 "/xyz/openbmc_project/state/host0",
869 "xyz.openbmc_project.State.Boot.Progress", "BootProgressLastUpdate",
870 [asyncResp](const boost::system::error_code& ec,
871 const uint64_t lastStateTime) {
872 if (ec)
873 {
874 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
875 return;
876 }
877
878 // BootProgressLastUpdate is the last time the BootProgress property
879 // was updated. The time is the Epoch time, number of microseconds
880 // since 1 Jan 1970 00::00::00 UTC."
881 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/
882 // yaml/xyz/openbmc_project/State/Boot/Progress.interface.yaml#L11
883
884 // Convert to ISO 8601 standard
885 asyncResp->res.jsonValue["BootProgress"]["LastStateTime"] =
886 redfish::time_utils::getDateTimeUintUs(lastStateTime);
887 });
888 }
889
890 /**
891 * @brief Retrieves boot override type over DBUS and fills out the response
892 *
893 * @param[in] asyncResp Shared pointer for generating response message.
894 *
895 * @return None.
896 */
897
898 inline void
getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)899 getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
900 {
901 sdbusplus::asio::getProperty<std::string>(
902 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
903 "/xyz/openbmc_project/control/host0/boot",
904 "xyz.openbmc_project.Control.Boot.Type", "BootType",
905 [asyncResp](const boost::system::error_code& ec,
906 const std::string& bootType) {
907 if (ec)
908 {
909 // not an error, don't have to have the interface
910 return;
911 }
912
913 BMCWEB_LOG_DEBUG("Boot type: {}", bootType);
914
915 asyncResp->res
916 .jsonValue["Boot"]
917 ["BootSourceOverrideMode@Redfish.AllowableValues"] =
918 nlohmann::json::array_t({"Legacy", "UEFI"});
919
920 auto rfType = dbusToRfBootType(bootType);
921 if (rfType.empty())
922 {
923 messages::internalError(asyncResp->res);
924 return;
925 }
926
927 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType;
928 });
929 }
930
931 /**
932 * @brief Retrieves boot override mode over DBUS and fills out the response
933 *
934 * @param[in] asyncResp Shared pointer for generating response message.
935 *
936 * @return None.
937 */
938
939 inline void
getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)940 getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
941 {
942 sdbusplus::asio::getProperty<std::string>(
943 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
944 "/xyz/openbmc_project/control/host0/boot",
945 "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
946 [asyncResp](const boost::system::error_code& ec,
947 const std::string& bootModeStr) {
948 if (ec)
949 {
950 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
951 messages::internalError(asyncResp->res);
952 return;
953 }
954
955 BMCWEB_LOG_DEBUG("Boot mode: {}", bootModeStr);
956
957 nlohmann::json::array_t allowed;
958 allowed.emplace_back("None");
959 allowed.emplace_back("Pxe");
960 allowed.emplace_back("Hdd");
961 allowed.emplace_back("Cd");
962 allowed.emplace_back("Diags");
963 allowed.emplace_back("BiosSetup");
964 allowed.emplace_back("Usb");
965
966 asyncResp->res
967 .jsonValue["Boot"]
968 ["BootSourceOverrideTarget@Redfish.AllowableValues"] =
969 std::move(allowed);
970 if (bootModeStr !=
971 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
972 {
973 auto rfMode = dbusToRfBootMode(bootModeStr);
974 if (!rfMode.empty())
975 {
976 asyncResp->res
977 .jsonValue["Boot"]["BootSourceOverrideTarget"] = rfMode;
978 }
979 }
980 });
981 }
982
983 /**
984 * @brief Retrieves boot override source over DBUS
985 *
986 * @param[in] asyncResp Shared pointer for generating response message.
987 *
988 * @return None.
989 */
990
991 inline void
getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)992 getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
993 {
994 sdbusplus::asio::getProperty<std::string>(
995 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
996 "/xyz/openbmc_project/control/host0/boot",
997 "xyz.openbmc_project.Control.Boot.Source", "BootSource",
998 [asyncResp](const boost::system::error_code& ec,
999 const std::string& bootSourceStr) {
1000 if (ec)
1001 {
1002 if (ec.value() == boost::asio::error::host_unreachable)
1003 {
1004 return;
1005 }
1006 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
1007 messages::internalError(asyncResp->res);
1008 return;
1009 }
1010
1011 BMCWEB_LOG_DEBUG("Boot source: {}", bootSourceStr);
1012
1013 auto rfSource = dbusToRfBootSource(bootSourceStr);
1014 if (!rfSource.empty())
1015 {
1016 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1017 rfSource;
1018 }
1019
1020 // Get BootMode as BootSourceOverrideTarget is constructed
1021 // from both BootSource and BootMode
1022 getBootOverrideMode(asyncResp);
1023 });
1024 }
1025
1026 /**
1027 * @brief This functions abstracts all the logic behind getting a
1028 * "BootSourceOverrideEnabled" property from an overall boot override enable
1029 * state
1030 *
1031 * @param[in] asyncResp Shared pointer for generating response message.
1032 *
1033 * @return None.
1034 */
1035
processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const bool bootOverrideEnableSetting)1036 inline void processBootOverrideEnable(
1037 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1038 const bool bootOverrideEnableSetting)
1039 {
1040 if (!bootOverrideEnableSetting)
1041 {
1042 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1043 "Disabled";
1044 return;
1045 }
1046
1047 // If boot source override is enabled, we need to check 'one_time'
1048 // property to set a correct value for the "BootSourceOverrideEnabled"
1049 sdbusplus::asio::getProperty<bool>(
1050 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1051 "/xyz/openbmc_project/control/host0/boot/one_time",
1052 "xyz.openbmc_project.Object.Enable", "Enabled",
1053 [asyncResp](const boost::system::error_code& ec, bool oneTimeSetting) {
1054 if (ec)
1055 {
1056 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
1057 messages::internalError(asyncResp->res);
1058 return;
1059 }
1060
1061 if (oneTimeSetting)
1062 {
1063 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1064 "Once";
1065 }
1066 else
1067 {
1068 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1069 "Continuous";
1070 }
1071 });
1072 }
1073
1074 /**
1075 * @brief Retrieves boot override enable over DBUS
1076 *
1077 * @param[in] asyncResp Shared pointer for generating response message.
1078 *
1079 * @return None.
1080 */
1081
1082 inline void
getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1083 getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1084 {
1085 sdbusplus::asio::getProperty<bool>(
1086 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1087 "/xyz/openbmc_project/control/host0/boot",
1088 "xyz.openbmc_project.Object.Enable", "Enabled",
1089 [asyncResp](const boost::system::error_code& ec,
1090 const bool bootOverrideEnable) {
1091 if (ec)
1092 {
1093 if (ec.value() == boost::asio::error::host_unreachable)
1094 {
1095 return;
1096 }
1097 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
1098 messages::internalError(asyncResp->res);
1099 return;
1100 }
1101
1102 processBootOverrideEnable(asyncResp, bootOverrideEnable);
1103 });
1104 }
1105
1106 /**
1107 * @brief Retrieves boot source override properties
1108 *
1109 * @param[in] asyncResp Shared pointer for generating response message.
1110 *
1111 * @return None.
1112 */
1113 inline void
getBootProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1114 getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1115 {
1116 BMCWEB_LOG_DEBUG("Get boot information.");
1117
1118 getBootOverrideSource(asyncResp);
1119 getBootOverrideType(asyncResp);
1120 getBootOverrideEnable(asyncResp);
1121 }
1122
1123 /**
1124 * @brief Retrieves the Last Reset Time
1125 *
1126 * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1127 * and power off. Even though this is the "system" Redfish object look at the
1128 * chassis D-Bus interface for the LastStateChangeTime since this has the
1129 * last power operation time.
1130 *
1131 * @param[in] asyncResp Shared pointer for generating response message.
1132 *
1133 * @return None.
1134 */
1135 inline void
getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1136 getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1137 {
1138 BMCWEB_LOG_DEBUG("Getting System Last Reset Time");
1139
1140 sdbusplus::asio::getProperty<uint64_t>(
1141 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1142 "/xyz/openbmc_project/state/chassis0",
1143 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime",
1144 [asyncResp](const boost::system::error_code& ec,
1145 uint64_t lastResetTime) {
1146 if (ec)
1147 {
1148 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1149 return;
1150 }
1151
1152 // LastStateChangeTime is epoch time, in milliseconds
1153 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1154 uint64_t lastResetTimeStamp = lastResetTime / 1000;
1155
1156 // Convert to ISO 8601 standard
1157 asyncResp->res.jsonValue["LastResetTime"] =
1158 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1159 });
1160 }
1161
1162 /**
1163 * @brief Retrieves the number of automatic boot Retry attempts allowed/left.
1164 *
1165 * The total number of automatic reboot retries allowed "RetryAttempts" and its
1166 * corresponding property "AttemptsLeft" that keeps track of the amount of
1167 * automatic retry attempts left are hosted in phosphor-state-manager through
1168 * dbus.
1169 *
1170 * @param[in] asyncResp Shared pointer for generating response message.
1171 *
1172 * @return None.
1173 */
getAutomaticRebootAttempts(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1174 inline void getAutomaticRebootAttempts(
1175 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1176 {
1177 BMCWEB_LOG_DEBUG("Get Automatic Retry policy");
1178
1179 sdbusplus::asio::getAllProperties(
1180 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
1181 "/xyz/openbmc_project/state/host0",
1182 "xyz.openbmc_project.Control.Boot.RebootAttempts",
1183 [asyncResp{asyncResp}](
1184 const boost::system::error_code& ec,
1185 const dbus::utility::DBusPropertiesMap& propertiesList) {
1186 if (ec)
1187 {
1188 if (ec.value() != EBADR)
1189 {
1190 BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
1191 messages::internalError(asyncResp->res);
1192 }
1193 return;
1194 }
1195
1196 const uint32_t* attemptsLeft = nullptr;
1197 const uint32_t* retryAttempts = nullptr;
1198
1199 const bool success = sdbusplus::unpackPropertiesNoThrow(
1200 dbus_utils::UnpackErrorPrinter(), propertiesList,
1201 "AttemptsLeft", attemptsLeft, "RetryAttempts", retryAttempts);
1202
1203 if (!success)
1204 {
1205 messages::internalError(asyncResp->res);
1206 return;
1207 }
1208
1209 if (attemptsLeft != nullptr)
1210 {
1211 asyncResp->res
1212 .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
1213 *attemptsLeft;
1214 }
1215
1216 if (retryAttempts != nullptr)
1217 {
1218 asyncResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] =
1219 *retryAttempts;
1220 }
1221 });
1222 }
1223
1224 /**
1225 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1226 *
1227 * @param[in] asyncResp Shared pointer for generating response message.
1228 *
1229 * @return None.
1230 */
1231 inline void
getAutomaticRetryPolicy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1232 getAutomaticRetryPolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1233 {
1234 BMCWEB_LOG_DEBUG("Get Automatic Retry policy");
1235
1236 sdbusplus::asio::getProperty<bool>(
1237 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1238 "/xyz/openbmc_project/control/host0/auto_reboot",
1239 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1240 [asyncResp](const boost::system::error_code& ec,
1241 bool autoRebootEnabled) {
1242 if (ec)
1243 {
1244 if (ec.value() != EBADR)
1245 {
1246 BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
1247 messages::internalError(asyncResp->res);
1248 }
1249 return;
1250 }
1251
1252 BMCWEB_LOG_DEBUG("Auto Reboot: {}", autoRebootEnabled);
1253 if (autoRebootEnabled)
1254 {
1255 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1256 "RetryAttempts";
1257 }
1258 else
1259 {
1260 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1261 "Disabled";
1262 }
1263 getAutomaticRebootAttempts(asyncResp);
1264
1265 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1266 // and RetryAttempts. OpenBMC only supports Disabled and
1267 // RetryAttempts.
1268 nlohmann::json::array_t allowed;
1269 allowed.emplace_back("Disabled");
1270 allowed.emplace_back("RetryAttempts");
1271 asyncResp->res
1272 .jsonValue["Boot"]
1273 ["AutomaticRetryConfig@Redfish.AllowableValues"] =
1274 std::move(allowed);
1275 });
1276 }
1277
1278 /**
1279 * @brief Sets RetryAttempts
1280 *
1281 * @param[in] asyncResp Shared pointer for generating response message.
1282 * @param[in] retryAttempts "AutomaticRetryAttempts" from request.
1283 *
1284 *@return None.
1285 */
1286
setAutomaticRetryAttempts(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const uint32_t retryAttempts)1287 inline void setAutomaticRetryAttempts(
1288 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1289 const uint32_t retryAttempts)
1290 {
1291 BMCWEB_LOG_DEBUG("Set Automatic Retry Attempts.");
1292 setDbusProperty(
1293 asyncResp, "Boot/AutomaticRetryAttempts",
1294 "xyz.openbmc_project.State.Host",
1295 sdbusplus::message::object_path("/xyz/openbmc_project/state/host0"),
1296 "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts",
1297 retryAttempts);
1298 }
1299
1300 inline computer_system::PowerRestorePolicyTypes
redfishPowerRestorePolicyFromDbus(std::string_view value)1301 redfishPowerRestorePolicyFromDbus(std::string_view value)
1302 {
1303 if (value ==
1304 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1305 {
1306 return computer_system::PowerRestorePolicyTypes::AlwaysOn;
1307 }
1308 if (value ==
1309 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff")
1310 {
1311 return computer_system::PowerRestorePolicyTypes::AlwaysOff;
1312 }
1313 if (value ==
1314 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
1315 {
1316 return computer_system::PowerRestorePolicyTypes::LastState;
1317 }
1318 if (value == "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None")
1319 {
1320 return computer_system::PowerRestorePolicyTypes::AlwaysOff;
1321 }
1322 return computer_system::PowerRestorePolicyTypes::Invalid;
1323 }
1324 /**
1325 * @brief Retrieves power restore policy over DBUS.
1326 *
1327 * @param[in] asyncResp Shared pointer for generating response message.
1328 *
1329 * @return None.
1330 */
1331 inline void
getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1332 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1333 {
1334 BMCWEB_LOG_DEBUG("Get power restore policy");
1335
1336 sdbusplus::asio::getProperty<std::string>(
1337 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1338 "/xyz/openbmc_project/control/host0/power_restore_policy",
1339 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1340 [asyncResp](const boost::system::error_code& ec,
1341 const std::string& policy) {
1342 if (ec)
1343 {
1344 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
1345 return;
1346 }
1347 computer_system::PowerRestorePolicyTypes restore =
1348 redfishPowerRestorePolicyFromDbus(policy);
1349 if (restore == computer_system::PowerRestorePolicyTypes::Invalid)
1350 {
1351 messages::internalError(asyncResp->res);
1352 return;
1353 }
1354
1355 asyncResp->res.jsonValue["PowerRestorePolicy"] = restore;
1356 });
1357 }
1358
1359 /**
1360 * @brief Stop Boot On Fault over DBUS.
1361 *
1362 * @param[in] asyncResp Shared pointer for generating response message.
1363 *
1364 * @return None.
1365 */
1366 inline void
getStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1367 getStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1368 {
1369 BMCWEB_LOG_DEBUG("Get Stop Boot On Fault");
1370
1371 sdbusplus::asio::getProperty<bool>(
1372 *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1373 "/xyz/openbmc_project/logging/settings",
1374 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError",
1375 [asyncResp](const boost::system::error_code& ec, bool value) {
1376 if (ec)
1377 {
1378 if (ec.value() != EBADR)
1379 {
1380 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
1381 messages::internalError(asyncResp->res);
1382 }
1383 return;
1384 }
1385
1386 if (value)
1387 {
1388 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] =
1389 computer_system::StopBootOnFault::AnyFault;
1390 }
1391 else
1392 {
1393 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] =
1394 computer_system::StopBootOnFault::Never;
1395 }
1396 });
1397 }
1398
1399 /**
1400 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1401 * TPM is required for booting the host.
1402 *
1403 * @param[in] asyncResp Shared pointer for generating response message.
1404 *
1405 * @return None.
1406 */
getTrustedModuleRequiredToBoot(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1407 inline void getTrustedModuleRequiredToBoot(
1408 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1409 {
1410 BMCWEB_LOG_DEBUG("Get TPM required to boot.");
1411 constexpr std::array<std::string_view, 1> interfaces = {
1412 "xyz.openbmc_project.Control.TPM.Policy"};
1413 dbus::utility::getSubTree(
1414 "/", 0, interfaces,
1415 [asyncResp](const boost::system::error_code& ec,
1416 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1417 if (ec)
1418 {
1419 BMCWEB_LOG_DEBUG(
1420 "DBUS response error on TPM.Policy GetSubTree{}", ec);
1421 // This is an optional D-Bus object so just return if
1422 // error occurs
1423 return;
1424 }
1425 if (subtree.empty())
1426 {
1427 // As noted above, this is an optional interface so just return
1428 // if there is no instance found
1429 return;
1430 }
1431
1432 /* When there is more than one TPMEnable object... */
1433 if (subtree.size() > 1)
1434 {
1435 BMCWEB_LOG_DEBUG(
1436 "DBUS response has more than 1 TPM Enable object:{}",
1437 subtree.size());
1438 // Throw an internal Error and return
1439 messages::internalError(asyncResp->res);
1440 return;
1441 }
1442
1443 // Make sure the Dbus response map has a service and objectPath
1444 // field
1445 if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1446 {
1447 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!");
1448 messages::internalError(asyncResp->res);
1449 return;
1450 }
1451
1452 const std::string& path = subtree[0].first;
1453 const std::string& serv = subtree[0].second.begin()->first;
1454
1455 // Valid TPM Enable object found, now reading the current value
1456 sdbusplus::asio::getProperty<bool>(
1457 *crow::connections::systemBus, serv, path,
1458 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1459 [asyncResp](const boost::system::error_code& ec2,
1460 bool tpmRequired) {
1461 if (ec2)
1462 {
1463 BMCWEB_LOG_ERROR(
1464 "D-BUS response error on TPM.Policy Get{}", ec2);
1465 messages::internalError(asyncResp->res);
1466 return;
1467 }
1468
1469 if (tpmRequired)
1470 {
1471 asyncResp->res
1472 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1473 "Required";
1474 }
1475 else
1476 {
1477 asyncResp->res
1478 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1479 "Disabled";
1480 }
1481 });
1482 });
1483 }
1484
1485 /**
1486 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1487 * TPM is required for booting the host.
1488 *
1489 * @param[in] asyncResp Shared pointer for generating response message.
1490 * @param[in] tpmRequired Value to set TPM Required To Boot property to.
1491 *
1492 * @return None.
1493 */
setTrustedModuleRequiredToBoot(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const bool tpmRequired)1494 inline void setTrustedModuleRequiredToBoot(
1495 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool tpmRequired)
1496 {
1497 BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot.");
1498 constexpr std::array<std::string_view, 1> interfaces = {
1499 "xyz.openbmc_project.Control.TPM.Policy"};
1500 dbus::utility::getSubTree(
1501 "/", 0, interfaces,
1502 [asyncResp,
1503 tpmRequired](const boost::system::error_code& ec,
1504 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1505 if (ec)
1506 {
1507 BMCWEB_LOG_ERROR(
1508 "DBUS response error on TPM.Policy GetSubTree{}", ec);
1509 messages::internalError(asyncResp->res);
1510 return;
1511 }
1512 if (subtree.empty())
1513 {
1514 messages::propertyValueNotInList(asyncResp->res,
1515 "ComputerSystem",
1516 "TrustedModuleRequiredToBoot");
1517 return;
1518 }
1519
1520 /* When there is more than one TPMEnable object... */
1521 if (subtree.size() > 1)
1522 {
1523 BMCWEB_LOG_DEBUG(
1524 "DBUS response has more than 1 TPM Enable object:{}",
1525 subtree.size());
1526 // Throw an internal Error and return
1527 messages::internalError(asyncResp->res);
1528 return;
1529 }
1530
1531 // Make sure the Dbus response map has a service and objectPath
1532 // field
1533 if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1534 {
1535 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!");
1536 messages::internalError(asyncResp->res);
1537 return;
1538 }
1539
1540 const std::string& path = subtree[0].first;
1541 const std::string& serv = subtree[0].second.begin()->first;
1542
1543 if (serv.empty())
1544 {
1545 BMCWEB_LOG_DEBUG("TPM.Policy service mapper error!");
1546 messages::internalError(asyncResp->res);
1547 return;
1548 }
1549
1550 // Valid TPM Enable object found, now setting the value
1551 setDbusProperty(asyncResp, "Boot/TrustedModuleRequiredToBoot", serv,
1552 path, "xyz.openbmc_project.Control.TPM.Policy",
1553 "TPMEnable", tpmRequired);
1554 });
1555 }
1556
1557 /**
1558 * @brief Sets boot properties into DBUS object(s).
1559 *
1560 * @param[in] asyncResp Shared pointer for generating response message.
1561 * @param[in] bootType The boot type to set.
1562 * @return Integer error code.
1563 */
setBootType(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootType)1564 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1565 const std::optional<std::string>& bootType)
1566 {
1567 std::string bootTypeStr;
1568
1569 if (!bootType)
1570 {
1571 return;
1572 }
1573
1574 // Source target specified
1575 BMCWEB_LOG_DEBUG("Boot type: {}", *bootType);
1576 // Figure out which DBUS interface and property to use
1577 if (*bootType == "Legacy")
1578 {
1579 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1580 }
1581 else if (*bootType == "UEFI")
1582 {
1583 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1584 }
1585 else
1586 {
1587 BMCWEB_LOG_DEBUG("Invalid property value for "
1588 "BootSourceOverrideMode: {}",
1589 *bootType);
1590 messages::propertyValueNotInList(asyncResp->res, *bootType,
1591 "BootSourceOverrideMode");
1592 return;
1593 }
1594
1595 // Act on validated parameters
1596 BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr);
1597
1598 setDbusProperty(asyncResp, "Boot/BootSourceOverrideMode",
1599 "xyz.openbmc_project.Settings",
1600 sdbusplus::message::object_path(
1601 "/xyz/openbmc_project/control/host0/boot"),
1602 "xyz.openbmc_project.Control.Boot.Type", "BootType",
1603 bootTypeStr);
1604 }
1605
1606 /**
1607 * @brief Sets boot properties into DBUS object(s).
1608 *
1609 * @param[in] asyncResp Shared pointer for generating response
1610 * message.
1611 * @param[in] bootType The boot type to set.
1612 * @return Integer error code.
1613 */
setBootEnable(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootEnable)1614 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1615 const std::optional<std::string>& bootEnable)
1616 {
1617 if (!bootEnable)
1618 {
1619 return;
1620 }
1621 // Source target specified
1622 BMCWEB_LOG_DEBUG("Boot enable: {}", *bootEnable);
1623
1624 bool bootOverrideEnable = false;
1625 bool bootOverridePersistent = false;
1626 // Figure out which DBUS interface and property to use
1627 if (*bootEnable == "Disabled")
1628 {
1629 bootOverrideEnable = false;
1630 }
1631 else if (*bootEnable == "Once")
1632 {
1633 bootOverrideEnable = true;
1634 bootOverridePersistent = false;
1635 }
1636 else if (*bootEnable == "Continuous")
1637 {
1638 bootOverrideEnable = true;
1639 bootOverridePersistent = true;
1640 }
1641 else
1642 {
1643 BMCWEB_LOG_DEBUG(
1644 "Invalid property value for BootSourceOverrideEnabled: {}",
1645 *bootEnable);
1646 messages::propertyValueNotInList(asyncResp->res, *bootEnable,
1647 "BootSourceOverrideEnabled");
1648 return;
1649 }
1650
1651 // Act on validated parameters
1652 BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable);
1653
1654 setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled",
1655 "xyz.openbmc_project.Settings",
1656 sdbusplus::message::object_path(
1657 "/xyz/openbmc_project/control/host0/boot"),
1658 "xyz.openbmc_project.Object.Enable", "Enabled",
1659 bootOverrideEnable);
1660
1661 if (!bootOverrideEnable)
1662 {
1663 return;
1664 }
1665
1666 // In case boot override is enabled we need to set correct value for the
1667 // 'one_time' enable DBus interface
1668 BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}",
1669 bootOverridePersistent);
1670
1671 setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled",
1672 "xyz.openbmc_project.Settings",
1673 sdbusplus::message::object_path(
1674 "/xyz/openbmc_project/control/host0/boot/one_time"),
1675 "xyz.openbmc_project.Object.Enable", "Enabled",
1676 !bootOverridePersistent);
1677 }
1678
1679 /**
1680 * @brief Sets boot properties into DBUS object(s).
1681 *
1682 * @param[in] asyncResp Shared pointer for generating response message.
1683 * @param[in] bootSource The boot source to set.
1684 *
1685 * @return Integer error code.
1686 */
1687 inline void
setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootSource)1688 setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1689 const std::optional<std::string>& bootSource)
1690 {
1691 std::string bootSourceStr;
1692 std::string bootModeStr;
1693
1694 if (!bootSource)
1695 {
1696 return;
1697 }
1698
1699 // Source target specified
1700 BMCWEB_LOG_DEBUG("Boot source: {}", *bootSource);
1701 // Figure out which DBUS interface and property to use
1702 if (assignBootParameters(asyncResp, *bootSource, bootSourceStr,
1703 bootModeStr) != 0)
1704 {
1705 BMCWEB_LOG_DEBUG(
1706 "Invalid property value for BootSourceOverrideTarget: {}",
1707 *bootSource);
1708 messages::propertyValueNotInList(asyncResp->res, *bootSource,
1709 "BootSourceTargetOverride");
1710 return;
1711 }
1712
1713 // Act on validated parameters
1714 BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr);
1715 BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr);
1716
1717 setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget",
1718 "xyz.openbmc_project.Settings",
1719 sdbusplus::message::object_path(
1720 "/xyz/openbmc_project/control/host0/boot"),
1721 "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1722 bootSourceStr);
1723 setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget",
1724 "xyz.openbmc_project.Settings",
1725 sdbusplus::message::object_path(
1726 "/xyz/openbmc_project/control/host0/boot"),
1727 "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1728 bootModeStr);
1729 }
1730
1731 /**
1732 * @brief Sets Boot source override properties.
1733 *
1734 * @param[in] asyncResp Shared pointer for generating response message.
1735 * @param[in] bootSource The boot source from incoming RF request.
1736 * @param[in] bootType The boot type from incoming RF request.
1737 * @param[in] bootEnable The boot override enable from incoming RF request.
1738 *
1739 * @return Integer error code.
1740 */
1741
1742 inline void
setBootProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootSource,const std::optional<std::string> & bootType,const std::optional<std::string> & bootEnable)1743 setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1744 const std::optional<std::string>& bootSource,
1745 const std::optional<std::string>& bootType,
1746 const std::optional<std::string>& bootEnable)
1747 {
1748 BMCWEB_LOG_DEBUG("Set boot information.");
1749
1750 setBootModeOrSource(asyncResp, bootSource);
1751 setBootType(asyncResp, bootType);
1752 setBootEnable(asyncResp, bootEnable);
1753 }
1754
1755 /**
1756 * @brief Sets AssetTag
1757 *
1758 * @param[in] asyncResp Shared pointer for generating response message.
1759 * @param[in] assetTag "AssetTag" from request.
1760 *
1761 * @return None.
1762 */
setAssetTag(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & assetTag)1763 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1764 const std::string& assetTag)
1765 {
1766 constexpr std::array<std::string_view, 1> interfaces = {
1767 "xyz.openbmc_project.Inventory.Item.System"};
1768 dbus::utility::getSubTree(
1769 "/xyz/openbmc_project/inventory", 0, interfaces,
1770 [asyncResp,
1771 assetTag](const boost::system::error_code& ec,
1772 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1773 if (ec)
1774 {
1775 BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec);
1776 messages::internalError(asyncResp->res);
1777 return;
1778 }
1779 if (subtree.empty())
1780 {
1781 BMCWEB_LOG_DEBUG("Can't find system D-Bus object!");
1782 messages::internalError(asyncResp->res);
1783 return;
1784 }
1785 // Assume only 1 system D-Bus object
1786 // Throw an error if there is more than 1
1787 if (subtree.size() > 1)
1788 {
1789 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus object!");
1790 messages::internalError(asyncResp->res);
1791 return;
1792 }
1793 if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1794 {
1795 BMCWEB_LOG_DEBUG("Asset Tag Set mapper error!");
1796 messages::internalError(asyncResp->res);
1797 return;
1798 }
1799
1800 const std::string& path = subtree[0].first;
1801 const std::string& service = subtree[0].second.begin()->first;
1802
1803 if (service.empty())
1804 {
1805 BMCWEB_LOG_DEBUG("Asset Tag Set service mapper error!");
1806 messages::internalError(asyncResp->res);
1807 return;
1808 }
1809
1810 setDbusProperty(asyncResp, "AssetTag", service, path,
1811 "xyz.openbmc_project.Inventory.Decorator.AssetTag",
1812 "AssetTag", assetTag);
1813 });
1814 }
1815
1816 /**
1817 * @brief Validate the specified stopBootOnFault is valid and return the
1818 * stopBootOnFault name associated with that string
1819 *
1820 * @param[in] stopBootOnFaultString String representing the desired
1821 * stopBootOnFault
1822 *
1823 * @return stopBootOnFault value or empty if incoming value is not valid
1824 */
1825 inline std::optional<bool>
validstopBootOnFault(const std::string & stopBootOnFaultString)1826 validstopBootOnFault(const std::string& stopBootOnFaultString)
1827 {
1828 if (stopBootOnFaultString == "AnyFault")
1829 {
1830 return true;
1831 }
1832
1833 if (stopBootOnFaultString == "Never")
1834 {
1835 return false;
1836 }
1837
1838 return std::nullopt;
1839 }
1840
1841 /**
1842 * @brief Sets stopBootOnFault
1843 *
1844 * @param[in] asyncResp Shared pointer for generating response message.
1845 * @param[in] stopBootOnFault "StopBootOnFault" from request.
1846 *
1847 * @return None.
1848 */
1849 inline void
setStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & stopBootOnFault)1850 setStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1851 const std::string& stopBootOnFault)
1852 {
1853 BMCWEB_LOG_DEBUG("Set Stop Boot On Fault.");
1854
1855 std::optional<bool> stopBootEnabled = validstopBootOnFault(stopBootOnFault);
1856 if (!stopBootEnabled)
1857 {
1858 BMCWEB_LOG_DEBUG("Invalid property value for StopBootOnFault: {}",
1859 stopBootOnFault);
1860 messages::propertyValueNotInList(asyncResp->res, stopBootOnFault,
1861 "StopBootOnFault");
1862 return;
1863 }
1864
1865 setDbusProperty(asyncResp, "Boot/StopBootOnFault",
1866 "xyz.openbmc_project.Settings",
1867 sdbusplus::message::object_path(
1868 "/xyz/openbmc_project/logging/settings"),
1869 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError",
1870 *stopBootEnabled);
1871 }
1872
1873 /**
1874 * @brief Sets automaticRetry (Auto Reboot)
1875 *
1876 * @param[in] asyncResp Shared pointer for generating response message.
1877 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request.
1878 *
1879 * @return None.
1880 */
1881 inline void
setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & automaticRetryConfig)1882 setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1883 const std::string& automaticRetryConfig)
1884 {
1885 BMCWEB_LOG_DEBUG("Set Automatic Retry.");
1886
1887 // OpenBMC only supports "Disabled" and "RetryAttempts".
1888 bool autoRebootEnabled = false;
1889
1890 if (automaticRetryConfig == "Disabled")
1891 {
1892 autoRebootEnabled = false;
1893 }
1894 else if (automaticRetryConfig == "RetryAttempts")
1895 {
1896 autoRebootEnabled = true;
1897 }
1898 else
1899 {
1900 BMCWEB_LOG_DEBUG("Invalid property value for AutomaticRetryConfig: {}",
1901 automaticRetryConfig);
1902 messages::propertyValueNotInList(asyncResp->res, automaticRetryConfig,
1903 "AutomaticRetryConfig");
1904 return;
1905 }
1906
1907 setDbusProperty(asyncResp, "Boot/AutomaticRetryConfig",
1908 "xyz.openbmc_project.Settings",
1909 sdbusplus::message::object_path(
1910 "/xyz/openbmc_project/control/host0/auto_reboot"),
1911 "xyz.openbmc_project.Control.Boot.RebootPolicy",
1912 "AutoReboot", autoRebootEnabled);
1913 }
1914
dbusPowerRestorePolicyFromRedfish(std::string_view policy)1915 inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy)
1916 {
1917 if (policy == "AlwaysOn")
1918 {
1919 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn";
1920 }
1921 if (policy == "AlwaysOff")
1922 {
1923 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff";
1924 }
1925 if (policy == "LastState")
1926 {
1927 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore";
1928 }
1929 return "";
1930 }
1931
1932 /**
1933 * @brief Sets power restore policy properties.
1934 *
1935 * @param[in] asyncResp Shared pointer for generating response message.
1936 * @param[in] policy power restore policy properties from request.
1937 *
1938 * @return None.
1939 */
1940 inline void
setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view policy)1941 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1942 std::string_view policy)
1943 {
1944 BMCWEB_LOG_DEBUG("Set power restore policy.");
1945
1946 std::string powerRestorePolicy = dbusPowerRestorePolicyFromRedfish(policy);
1947
1948 if (powerRestorePolicy.empty())
1949 {
1950 messages::propertyValueNotInList(asyncResp->res, policy,
1951 "PowerRestorePolicy");
1952 return;
1953 }
1954
1955 setDbusProperty(
1956 asyncResp, "PowerRestorePolicy", "xyz.openbmc_project.Settings",
1957 sdbusplus::message::object_path(
1958 "/xyz/openbmc_project/control/host0/power_restore_policy"),
1959 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1960 powerRestorePolicy);
1961 }
1962
1963 /**
1964 * @brief Retrieves provisioning status
1965 *
1966 * @param[in] asyncResp Shared pointer for completing asynchronous
1967 * calls.
1968 *
1969 * @return None.
1970 */
1971 inline void
getProvisioningStatus(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1972 getProvisioningStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1973 {
1974 BMCWEB_LOG_DEBUG("Get OEM information.");
1975 sdbusplus::asio::getAllProperties(
1976 *crow::connections::systemBus, "xyz.openbmc_project.PFR.Manager",
1977 "/xyz/openbmc_project/pfr", "xyz.openbmc_project.PFR.Attributes",
1978 [asyncResp](const boost::system::error_code& ec,
1979 const dbus::utility::DBusPropertiesMap& propertiesList) {
1980 nlohmann::json& oemPFR =
1981 asyncResp->res
1982 .jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1983 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1984 "#OpenBMCComputerSystem.v1_0_0.OpenBmc";
1985 oemPFR["@odata.type"] =
1986 "#OpenBMCComputerSystem.FirmwareProvisioning";
1987
1988 if (ec)
1989 {
1990 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
1991 // not an error, don't have to have the interface
1992 oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
1993 FirmwareProvisioningStatus::NotProvisioned;
1994 return;
1995 }
1996
1997 const bool* provState = nullptr;
1998 const bool* lockState = nullptr;
1999
2000 const bool success = sdbusplus::unpackPropertiesNoThrow(
2001 dbus_utils::UnpackErrorPrinter(), propertiesList,
2002 "UfmProvisioned", provState, "UfmLocked", lockState);
2003
2004 if (!success)
2005 {
2006 messages::internalError(asyncResp->res);
2007 return;
2008 }
2009
2010 if ((provState == nullptr) || (lockState == nullptr))
2011 {
2012 BMCWEB_LOG_DEBUG("Unable to get PFR attributes.");
2013 messages::internalError(asyncResp->res);
2014 return;
2015 }
2016
2017 if (*provState)
2018 {
2019 if (*lockState)
2020 {
2021 oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2022 FirmwareProvisioningStatus::ProvisionedAndLocked;
2023 }
2024 else
2025 {
2026 oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2027 FirmwareProvisioningStatus::ProvisionedButNotLocked;
2028 }
2029 }
2030 else
2031 {
2032 oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2033 FirmwareProvisioningStatus::NotProvisioned;
2034 }
2035 });
2036 }
2037
2038 /**
2039 * @brief Translate the PowerMode string to enum value
2040 *
2041 * @param[in] modeString PowerMode string to be translated
2042 *
2043 * @return PowerMode enum
2044 */
2045 inline computer_system::PowerMode
translatePowerModeString(const std::string & modeString)2046 translatePowerModeString(const std::string& modeString)
2047 {
2048 using PowerMode = computer_system::PowerMode;
2049
2050 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
2051 {
2052 return PowerMode::Static;
2053 }
2054 if (modeString ==
2055 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
2056 {
2057 return PowerMode::MaximumPerformance;
2058 }
2059 if (modeString ==
2060 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
2061 {
2062 return PowerMode::PowerSaving;
2063 }
2064 if (modeString ==
2065 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance")
2066 {
2067 return PowerMode::BalancedPerformance;
2068 }
2069 if (modeString ==
2070 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance")
2071 {
2072 return PowerMode::EfficiencyFavorPerformance;
2073 }
2074 if (modeString ==
2075 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower")
2076 {
2077 return PowerMode::EfficiencyFavorPower;
2078 }
2079 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
2080 {
2081 return PowerMode::OEM;
2082 }
2083 // Any other values would be invalid
2084 BMCWEB_LOG_ERROR("PowerMode value was not valid: {}", modeString);
2085 return PowerMode::Invalid;
2086 }
2087
2088 inline void
afterGetPowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & properties)2089 afterGetPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2090 const boost::system::error_code& ec,
2091 const dbus::utility::DBusPropertiesMap& properties)
2092 {
2093 if (ec)
2094 {
2095 BMCWEB_LOG_ERROR("DBUS response error on PowerMode GetAll: {}", ec);
2096 messages::internalError(asyncResp->res);
2097 return;
2098 }
2099
2100 std::string powerMode;
2101 const std::vector<std::string>* allowedModes = nullptr;
2102 const bool success = sdbusplus::unpackPropertiesNoThrow(
2103 dbus_utils::UnpackErrorPrinter(), properties, "PowerMode", powerMode,
2104 "AllowedPowerModes", allowedModes);
2105
2106 if (!success)
2107 {
2108 messages::internalError(asyncResp->res);
2109 return;
2110 }
2111
2112 nlohmann::json::array_t modeList;
2113 if (allowedModes == nullptr)
2114 {
2115 modeList.emplace_back("Static");
2116 modeList.emplace_back("MaximumPerformance");
2117 modeList.emplace_back("PowerSaving");
2118 }
2119 else
2120 {
2121 for (const auto& aMode : *allowedModes)
2122 {
2123 computer_system::PowerMode modeValue =
2124 translatePowerModeString(aMode);
2125 if (modeValue == computer_system::PowerMode::Invalid)
2126 {
2127 messages::internalError(asyncResp->res);
2128 continue;
2129 }
2130 modeList.emplace_back(modeValue);
2131 }
2132 }
2133 asyncResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = modeList;
2134
2135 BMCWEB_LOG_DEBUG("Current power mode: {}", powerMode);
2136 const computer_system::PowerMode modeValue =
2137 translatePowerModeString(powerMode);
2138 if (modeValue == computer_system::PowerMode::Invalid)
2139 {
2140 messages::internalError(asyncResp->res);
2141 return;
2142 }
2143 asyncResp->res.jsonValue["PowerMode"] = modeValue;
2144 }
2145 /**
2146 * @brief Retrieves system power mode
2147 *
2148 * @param[in] asyncResp Shared pointer for generating response message.
2149 *
2150 * @return None.
2151 */
getPowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2152 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2153 {
2154 BMCWEB_LOG_DEBUG("Get power mode.");
2155
2156 // Get Power Mode object path:
2157 constexpr std::array<std::string_view, 1> interfaces = {
2158 "xyz.openbmc_project.Control.Power.Mode"};
2159 dbus::utility::getSubTree(
2160 "/", 0, interfaces,
2161 [asyncResp](const boost::system::error_code& ec,
2162 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2163 if (ec)
2164 {
2165 BMCWEB_LOG_DEBUG(
2166 "DBUS response error on Power.Mode GetSubTree {}", ec);
2167 // This is an optional D-Bus object so just return if
2168 // error occurs
2169 return;
2170 }
2171 if (subtree.empty())
2172 {
2173 // As noted above, this is an optional interface so just return
2174 // if there is no instance found
2175 return;
2176 }
2177 if (subtree.size() > 1)
2178 {
2179 // More then one PowerMode object is not supported and is an
2180 // error
2181 BMCWEB_LOG_DEBUG(
2182 "Found more than 1 system D-Bus Power.Mode objects: {}",
2183 subtree.size());
2184 messages::internalError(asyncResp->res);
2185 return;
2186 }
2187 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2188 {
2189 BMCWEB_LOG_DEBUG("Power.Mode mapper error!");
2190 messages::internalError(asyncResp->res);
2191 return;
2192 }
2193 const std::string& path = subtree[0].first;
2194 const std::string& service = subtree[0].second.begin()->first;
2195 if (service.empty())
2196 {
2197 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!");
2198 messages::internalError(asyncResp->res);
2199 return;
2200 }
2201
2202 // Valid Power Mode object found, now read the mode properties
2203 sdbusplus::asio::getAllProperties(
2204 *crow::connections::systemBus, service, path,
2205 "xyz.openbmc_project.Control.Power.Mode",
2206 [asyncResp](
2207 const boost::system::error_code& ec2,
2208 const dbus::utility::DBusPropertiesMap& properties) {
2209 afterGetPowerMode(asyncResp, ec2, properties);
2210 });
2211 });
2212 }
2213
2214 /**
2215 * @brief Validate the specified mode is valid and return the PowerMode
2216 * name associated with that string
2217 *
2218 * @param[in] asyncResp Shared pointer for generating response message.
2219 * @param[in] modeValue String representing the desired PowerMode
2220 *
2221 * @return PowerMode value or empty string if mode is not valid
2222 */
2223 inline std::string
validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const nlohmann::json & modeValue)2224 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2225 const nlohmann::json& modeValue)
2226 {
2227 using PowerMode = computer_system::PowerMode;
2228 std::string mode;
2229
2230 if (modeValue == PowerMode::Static)
2231 {
2232 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2233 }
2234 else if (modeValue == PowerMode::MaximumPerformance)
2235 {
2236 mode =
2237 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2238 }
2239 else if (modeValue == PowerMode::PowerSaving)
2240 {
2241 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2242 }
2243 else if (modeValue == PowerMode::BalancedPerformance)
2244 {
2245 mode =
2246 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance";
2247 }
2248 else if (modeValue == PowerMode::EfficiencyFavorPerformance)
2249 {
2250 mode =
2251 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance";
2252 }
2253 else if (modeValue == PowerMode::EfficiencyFavorPower)
2254 {
2255 mode =
2256 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower";
2257 }
2258 else
2259 {
2260 messages::propertyValueNotInList(asyncResp->res, modeValue.dump(),
2261 "PowerMode");
2262 }
2263 return mode;
2264 }
2265
2266 /**
2267 * @brief Sets system power mode.
2268 *
2269 * @param[in] asyncResp Shared pointer for generating response message.
2270 * @param[in] pmode System power mode from request.
2271 *
2272 * @return None.
2273 */
setPowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pmode)2274 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2275 const std::string& pmode)
2276 {
2277 BMCWEB_LOG_DEBUG("Set power mode.");
2278
2279 std::string powerMode = validatePowerMode(asyncResp, pmode);
2280 if (powerMode.empty())
2281 {
2282 return;
2283 }
2284
2285 // Get Power Mode object path:
2286 constexpr std::array<std::string_view, 1> interfaces = {
2287 "xyz.openbmc_project.Control.Power.Mode"};
2288 dbus::utility::getSubTree(
2289 "/", 0, interfaces,
2290 [asyncResp,
2291 powerMode](const boost::system::error_code& ec,
2292 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2293 if (ec)
2294 {
2295 BMCWEB_LOG_ERROR(
2296 "DBUS response error on Power.Mode GetSubTree {}", ec);
2297 // This is an optional D-Bus object, but user attempted to patch
2298 messages::internalError(asyncResp->res);
2299 return;
2300 }
2301 if (subtree.empty())
2302 {
2303 // This is an optional D-Bus object, but user attempted to patch
2304 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2305 "PowerMode");
2306 return;
2307 }
2308 if (subtree.size() > 1)
2309 {
2310 // More then one PowerMode object is not supported and is an
2311 // error
2312 BMCWEB_LOG_DEBUG(
2313 "Found more than 1 system D-Bus Power.Mode objects: {}",
2314 subtree.size());
2315 messages::internalError(asyncResp->res);
2316 return;
2317 }
2318 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2319 {
2320 BMCWEB_LOG_DEBUG("Power.Mode mapper error!");
2321 messages::internalError(asyncResp->res);
2322 return;
2323 }
2324 const std::string& path = subtree[0].first;
2325 const std::string& service = subtree[0].second.begin()->first;
2326 if (service.empty())
2327 {
2328 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!");
2329 messages::internalError(asyncResp->res);
2330 return;
2331 }
2332
2333 BMCWEB_LOG_DEBUG("Setting power mode({}) -> {}", powerMode, path);
2334
2335 // Set the Power Mode property
2336 setDbusProperty(asyncResp, "PowerMode", service, path,
2337 "xyz.openbmc_project.Control.Power.Mode",
2338 "PowerMode", powerMode);
2339 });
2340 }
2341
2342 /**
2343 * @brief Translates watchdog timeout action DBUS property value to redfish.
2344 *
2345 * @param[in] dbusAction The watchdog timeout action in D-BUS.
2346 *
2347 * @return Returns as a string, the timeout action in Redfish terms. If
2348 * translation cannot be done, returns an empty string.
2349 */
dbusToRfWatchdogAction(const std::string & dbusAction)2350 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2351 {
2352 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2353 {
2354 return "None";
2355 }
2356 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2357 {
2358 return "ResetSystem";
2359 }
2360 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2361 {
2362 return "PowerDown";
2363 }
2364 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2365 {
2366 return "PowerCycle";
2367 }
2368
2369 return "";
2370 }
2371
2372 /**
2373 *@brief Translates timeout action from Redfish to DBUS property value.
2374 *
2375 *@param[in] rfAction The timeout action in Redfish.
2376 *
2377 *@return Returns as a string, the time_out action as expected by DBUS.
2378 *If translation cannot be done, returns an empty string.
2379 */
2380
rfToDbusWDTTimeOutAct(const std::string & rfAction)2381 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2382 {
2383 if (rfAction == "None")
2384 {
2385 return "xyz.openbmc_project.State.Watchdog.Action.None";
2386 }
2387 if (rfAction == "PowerCycle")
2388 {
2389 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2390 }
2391 if (rfAction == "PowerDown")
2392 {
2393 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2394 }
2395 if (rfAction == "ResetSystem")
2396 {
2397 return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2398 }
2399
2400 return "";
2401 }
2402
2403 /**
2404 * @brief Retrieves host watchdog timer properties over DBUS
2405 *
2406 * @param[in] asyncResp Shared pointer for completing asynchronous calls.
2407 *
2408 * @return None.
2409 */
2410 inline void
getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2411 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2412 {
2413 BMCWEB_LOG_DEBUG("Get host watchodg");
2414 sdbusplus::asio::getAllProperties(
2415 *crow::connections::systemBus, "xyz.openbmc_project.Watchdog",
2416 "/xyz/openbmc_project/watchdog/host0",
2417 "xyz.openbmc_project.State.Watchdog",
2418 [asyncResp](const boost::system::error_code& ec,
2419 const dbus::utility::DBusPropertiesMap& properties) {
2420 if (ec)
2421 {
2422 // watchdog service is stopped
2423 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
2424 return;
2425 }
2426
2427 BMCWEB_LOG_DEBUG("Got {} wdt prop.", properties.size());
2428
2429 nlohmann::json& hostWatchdogTimer =
2430 asyncResp->res.jsonValue["HostWatchdogTimer"];
2431
2432 // watchdog service is running/enabled
2433 hostWatchdogTimer["Status"]["State"] = resource::State::Enabled;
2434
2435 const bool* enabled = nullptr;
2436 const std::string* expireAction = nullptr;
2437
2438 const bool success = sdbusplus::unpackPropertiesNoThrow(
2439 dbus_utils::UnpackErrorPrinter(), properties, "Enabled",
2440 enabled, "ExpireAction", expireAction);
2441
2442 if (!success)
2443 {
2444 messages::internalError(asyncResp->res);
2445 return;
2446 }
2447
2448 if (enabled != nullptr)
2449 {
2450 hostWatchdogTimer["FunctionEnabled"] = *enabled;
2451 }
2452
2453 if (expireAction != nullptr)
2454 {
2455 std::string action = dbusToRfWatchdogAction(*expireAction);
2456 if (action.empty())
2457 {
2458 messages::internalError(asyncResp->res);
2459 return;
2460 }
2461 hostWatchdogTimer["TimeoutAction"] = action;
2462 }
2463 });
2464 }
2465
2466 /**
2467 * @brief Sets Host WatchDog Timer properties.
2468 *
2469 * @param[in] asyncResp Shared pointer for generating response message.
2470 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming
2471 * RF request.
2472 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2473 *
2474 * @return None.
2475 */
2476 inline void
setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<bool> wdtEnable,const std::optional<std::string> & wdtTimeOutAction)2477 setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2478 const std::optional<bool> wdtEnable,
2479 const std::optional<std::string>& wdtTimeOutAction)
2480 {
2481 BMCWEB_LOG_DEBUG("Set host watchdog");
2482
2483 if (wdtTimeOutAction)
2484 {
2485 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2486 // check if TimeOut Action is Valid
2487 if (wdtTimeOutActStr.empty())
2488 {
2489 BMCWEB_LOG_DEBUG("Unsupported value for TimeoutAction: {}",
2490 *wdtTimeOutAction);
2491 messages::propertyValueNotInList(asyncResp->res, *wdtTimeOutAction,
2492 "TimeoutAction");
2493 return;
2494 }
2495
2496 setDbusProperty(asyncResp, "HostWatchdogTimer/TimeoutAction",
2497 "xyz.openbmc_project.Watchdog",
2498 sdbusplus::message::object_path(
2499 "/xyz/openbmc_project/watchdog/host0"),
2500 "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2501 wdtTimeOutActStr);
2502 }
2503
2504 if (wdtEnable)
2505 {
2506 setDbusProperty(asyncResp, "HostWatchdogTimer/FunctionEnabled",
2507 "xyz.openbmc_project.Watchdog",
2508 sdbusplus::message::object_path(
2509 "/xyz/openbmc_project/watchdog/host0"),
2510 "xyz.openbmc_project.State.Watchdog", "Enabled",
2511 *wdtEnable);
2512 }
2513 }
2514
2515 /**
2516 * @brief Parse the Idle Power Saver properties into json
2517 *
2518 * @param[in] asyncResp Shared pointer for completing asynchronous calls.
2519 * @param[in] properties IPS property data from DBus.
2520 *
2521 * @return true if successful
2522 */
2523 inline bool
parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & properties)2524 parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2525 const dbus::utility::DBusPropertiesMap& properties)
2526 {
2527 const bool* enabled = nullptr;
2528 const uint8_t* enterUtilizationPercent = nullptr;
2529 const uint64_t* enterDwellTime = nullptr;
2530 const uint8_t* exitUtilizationPercent = nullptr;
2531 const uint64_t* exitDwellTime = nullptr;
2532
2533 const bool success = sdbusplus::unpackPropertiesNoThrow(
2534 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled,
2535 "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime",
2536 enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent,
2537 "ExitDwellTime", exitDwellTime);
2538
2539 if (!success)
2540 {
2541 return false;
2542 }
2543
2544 if (enabled != nullptr)
2545 {
2546 asyncResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled;
2547 }
2548
2549 if (enterUtilizationPercent != nullptr)
2550 {
2551 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] =
2552 *enterUtilizationPercent;
2553 }
2554
2555 if (enterDwellTime != nullptr)
2556 {
2557 const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime);
2558 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2559 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2560 .count();
2561 }
2562
2563 if (exitUtilizationPercent != nullptr)
2564 {
2565 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] =
2566 *exitUtilizationPercent;
2567 }
2568
2569 if (exitDwellTime != nullptr)
2570 {
2571 const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime);
2572 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2573 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2574 .count();
2575 }
2576
2577 return true;
2578 }
2579
2580 /**
2581 * @brief Retrieves host watchdog timer properties over DBUS
2582 *
2583 * @param[in] asyncResp Shared pointer for completing asynchronous calls.
2584 *
2585 * @return None.
2586 */
2587 inline void
getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2588 getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2589 {
2590 BMCWEB_LOG_DEBUG("Get idle power saver parameters");
2591
2592 // Get IdlePowerSaver object path:
2593 constexpr std::array<std::string_view, 1> interfaces = {
2594 "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2595 dbus::utility::getSubTree(
2596 "/", 0, interfaces,
2597 [asyncResp](const boost::system::error_code& ec,
2598 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2599 if (ec)
2600 {
2601 BMCWEB_LOG_ERROR(
2602 "DBUS response error on Power.IdlePowerSaver GetSubTree {}",
2603 ec);
2604 messages::internalError(asyncResp->res);
2605 return;
2606 }
2607 if (subtree.empty())
2608 {
2609 // This is an optional interface so just return
2610 // if there is no instance found
2611 BMCWEB_LOG_DEBUG("No instances found");
2612 return;
2613 }
2614 if (subtree.size() > 1)
2615 {
2616 // More then one PowerIdlePowerSaver object is not supported and
2617 // is an error
2618 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus "
2619 "Power.IdlePowerSaver objects: {}",
2620 subtree.size());
2621 messages::internalError(asyncResp->res);
2622 return;
2623 }
2624 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2625 {
2626 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!");
2627 messages::internalError(asyncResp->res);
2628 return;
2629 }
2630 const std::string& path = subtree[0].first;
2631 const std::string& service = subtree[0].second.begin()->first;
2632 if (service.empty())
2633 {
2634 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!");
2635 messages::internalError(asyncResp->res);
2636 return;
2637 }
2638
2639 // Valid IdlePowerSaver object found, now read the current values
2640 sdbusplus::asio::getAllProperties(
2641 *crow::connections::systemBus, service, path,
2642 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2643 [asyncResp](
2644 const boost::system::error_code& ec2,
2645 const dbus::utility::DBusPropertiesMap& properties) {
2646 if (ec2)
2647 {
2648 BMCWEB_LOG_ERROR(
2649 "DBUS response error on IdlePowerSaver GetAll: {}",
2650 ec2);
2651 messages::internalError(asyncResp->res);
2652 return;
2653 }
2654
2655 if (!parseIpsProperties(asyncResp, properties))
2656 {
2657 messages::internalError(asyncResp->res);
2658 return;
2659 }
2660 });
2661 });
2662
2663 BMCWEB_LOG_DEBUG("EXIT: Get idle power saver parameters");
2664 }
2665
2666 /**
2667 * @brief Sets Idle Power Saver properties.
2668 *
2669 * @param[in] asyncResp Shared pointer for generating response message.
2670 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming
2671 * RF request.
2672 * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2673 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2674 * before entering idle state.
2675 * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2676 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2677 * before exiting idle state
2678 *
2679 * @return None.
2680 */
setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<bool> ipsEnable,const std::optional<uint8_t> ipsEnterUtil,const std::optional<uint64_t> ipsEnterTime,const std::optional<uint8_t> ipsExitUtil,const std::optional<uint64_t> ipsExitTime)2681 inline void setIdlePowerSaver(
2682 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2683 const std::optional<bool> ipsEnable,
2684 const std::optional<uint8_t> ipsEnterUtil,
2685 const std::optional<uint64_t> ipsEnterTime,
2686 const std::optional<uint8_t> ipsExitUtil,
2687 const std::optional<uint64_t> ipsExitTime)
2688 {
2689 BMCWEB_LOG_DEBUG("Set idle power saver properties");
2690
2691 // Get IdlePowerSaver object path:
2692 constexpr std::array<std::string_view, 1> interfaces = {
2693 "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2694 dbus::utility::getSubTree(
2695 "/", 0, interfaces,
2696 [asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2697 ipsExitTime](const boost::system::error_code& ec,
2698 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2699 if (ec)
2700 {
2701 BMCWEB_LOG_ERROR(
2702 "DBUS response error on Power.IdlePowerSaver GetSubTree {}",
2703 ec);
2704 messages::internalError(asyncResp->res);
2705 return;
2706 }
2707 if (subtree.empty())
2708 {
2709 // This is an optional D-Bus object, but user attempted to patch
2710 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2711 "IdlePowerSaver");
2712 return;
2713 }
2714 if (subtree.size() > 1)
2715 {
2716 // More then one PowerIdlePowerSaver object is not supported and
2717 // is an error
2718 BMCWEB_LOG_DEBUG(
2719 "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}",
2720 subtree.size());
2721 messages::internalError(asyncResp->res);
2722 return;
2723 }
2724 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2725 {
2726 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!");
2727 messages::internalError(asyncResp->res);
2728 return;
2729 }
2730 const std::string& path = subtree[0].first;
2731 const std::string& service = subtree[0].second.begin()->first;
2732 if (service.empty())
2733 {
2734 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!");
2735 messages::internalError(asyncResp->res);
2736 return;
2737 }
2738
2739 // Valid Power IdlePowerSaver object found, now set any values that
2740 // need to be updated
2741
2742 if (ipsEnable)
2743 {
2744 setDbusProperty(
2745 asyncResp, "IdlePowerSaver/Enabled", service, path,
2746 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2747 "Enabled", *ipsEnable);
2748 }
2749 if (ipsEnterUtil)
2750 {
2751 setDbusProperty(
2752 asyncResp, "IdlePowerSaver/EnterUtilizationPercent",
2753 service, path,
2754 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2755 "EnterUtilizationPercent", *ipsEnterUtil);
2756 }
2757 if (ipsEnterTime)
2758 {
2759 // Convert from seconds into milliseconds for DBus
2760 const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2761 setDbusProperty(
2762 asyncResp, "IdlePowerSaver/EnterDwellTimeSeconds", service,
2763 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2764 "EnterDwellTime", timeMilliseconds);
2765 }
2766 if (ipsExitUtil)
2767 {
2768 setDbusProperty(
2769 asyncResp, "IdlePowerSaver/ExitUtilizationPercent", service,
2770 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2771 "ExitUtilizationPercent", *ipsExitUtil);
2772 }
2773 if (ipsExitTime)
2774 {
2775 // Convert from seconds into milliseconds for DBus
2776 const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2777 setDbusProperty(
2778 asyncResp, "IdlePowerSaver/ExitDwellTimeSeconds", service,
2779 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2780 "ExitDwellTime", timeMilliseconds);
2781 }
2782 });
2783
2784 BMCWEB_LOG_DEBUG("EXIT: Set idle power saver parameters");
2785 }
2786
handleComputerSystemCollectionHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2787 inline void handleComputerSystemCollectionHead(
2788 crow::App& app, const crow::Request& req,
2789 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2790 {
2791 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2792 {
2793 return;
2794 }
2795 asyncResp->res.addHeader(
2796 boost::beast::http::field::link,
2797 "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby");
2798 }
2799
handleComputerSystemCollectionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2800 inline void handleComputerSystemCollectionGet(
2801 crow::App& app, const crow::Request& req,
2802 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2803 {
2804 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2805 {
2806 return;
2807 }
2808
2809 asyncResp->res.addHeader(
2810 boost::beast::http::field::link,
2811 "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby");
2812 asyncResp->res.jsonValue["@odata.type"] =
2813 "#ComputerSystemCollection.ComputerSystemCollection";
2814 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2815 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2816
2817 nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"];
2818 ifaceArray = nlohmann::json::array();
2819 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2820 {
2821 asyncResp->res.jsonValue["Members@odata.count"] = 0;
2822 // Option currently returns no systems. TBD
2823 return;
2824 }
2825 asyncResp->res.jsonValue["Members@odata.count"] = 1;
2826 nlohmann::json::object_t system;
2827 system["@odata.id"] = boost::urls::format("/redfish/v1/Systems/{}",
2828 BMCWEB_REDFISH_SYSTEM_URI_NAME);
2829 ifaceArray.emplace_back(std::move(system));
2830
2831 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
2832 {
2833 BMCWEB_LOG_DEBUG("Hypervisor is available");
2834 asyncResp->res.jsonValue["Members@odata.count"] = 2;
2835
2836 nlohmann::json::object_t hypervisor;
2837 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor";
2838 ifaceArray.emplace_back(std::move(hypervisor));
2839 }
2840 }
2841
2842 /**
2843 * Function transceives data with dbus directly.
2844 */
doNMI(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2845 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2846 {
2847 constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2848 constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2849 constexpr const char* interfaceName =
2850 "xyz.openbmc_project.Control.Host.NMI";
2851 constexpr const char* method = "NMI";
2852
2853 crow::connections::systemBus->async_method_call(
2854 [asyncResp](const boost::system::error_code& ec) {
2855 if (ec)
2856 {
2857 BMCWEB_LOG_ERROR(" Bad D-Bus request error: {}", ec);
2858 messages::internalError(asyncResp->res);
2859 return;
2860 }
2861 messages::success(asyncResp->res);
2862 },
2863 serviceName, objectPath, interfaceName, method);
2864 }
2865
handleComputerSystemResetActionPost(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)2866 inline void handleComputerSystemResetActionPost(
2867 crow::App& app, const crow::Request& req,
2868 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2869 const std::string& systemName)
2870 {
2871 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2872 {
2873 return;
2874 }
2875
2876 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
2877 {
2878 if (systemName == "hypervisor")
2879 {
2880 handleHypervisorSystemResetPost(req, asyncResp);
2881 return;
2882 }
2883 }
2884
2885 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
2886 {
2887 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2888 systemName);
2889 return;
2890 }
2891 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2892 {
2893 // Option currently returns no systems. TBD
2894 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2895 systemName);
2896 return;
2897 }
2898 std::string resetType;
2899 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
2900 {
2901 return;
2902 }
2903
2904 // Get the command and host vs. chassis
2905 std::string command;
2906 bool hostCommand = true;
2907 if ((resetType == "On") || (resetType == "ForceOn"))
2908 {
2909 command = "xyz.openbmc_project.State.Host.Transition.On";
2910 hostCommand = true;
2911 }
2912 else if (resetType == "ForceOff")
2913 {
2914 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2915 hostCommand = false;
2916 }
2917 else if (resetType == "ForceRestart")
2918 {
2919 command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2920 hostCommand = true;
2921 }
2922 else if (resetType == "GracefulShutdown")
2923 {
2924 command = "xyz.openbmc_project.State.Host.Transition.Off";
2925 hostCommand = true;
2926 }
2927 else if (resetType == "GracefulRestart")
2928 {
2929 command =
2930 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2931 hostCommand = true;
2932 }
2933 else if (resetType == "PowerCycle")
2934 {
2935 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2936 hostCommand = true;
2937 }
2938 else if (resetType == "Nmi")
2939 {
2940 doNMI(asyncResp);
2941 return;
2942 }
2943 else
2944 {
2945 messages::actionParameterUnknown(asyncResp->res, "Reset", resetType);
2946 return;
2947 }
2948 sdbusplus::message::object_path statePath("/xyz/openbmc_project/state");
2949
2950 if (hostCommand)
2951 {
2952 setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Host",
2953 statePath / "host0", "xyz.openbmc_project.State.Host",
2954 "RequestedHostTransition", command);
2955 }
2956 else
2957 {
2958 setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Chassis",
2959 statePath / "chassis0",
2960 "xyz.openbmc_project.State.Chassis",
2961 "RequestedPowerTransition", command);
2962 }
2963 }
2964
handleComputerSystemHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)2965 inline void handleComputerSystemHead(
2966 App& app, const crow::Request& req,
2967 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2968 const std::string& /*systemName*/)
2969 {
2970 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2971 {
2972 return;
2973 }
2974
2975 asyncResp->res.addHeader(
2976 boost::beast::http::field::link,
2977 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
2978 }
2979
afterPortRequest(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::vector<std::tuple<std::string,std::string,bool>> & socketData)2980 inline void afterPortRequest(
2981 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2982 const boost::system::error_code& ec,
2983 const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
2984 {
2985 if (ec)
2986 {
2987 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
2988 messages::internalError(asyncResp->res);
2989 return;
2990 }
2991 for (const auto& data : socketData)
2992 {
2993 const std::string& socketPath = get<0>(data);
2994 const std::string& protocolName = get<1>(data);
2995 bool isProtocolEnabled = get<2>(data);
2996 nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"];
2997 dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled;
2998 // need to retrieve port number for
2999 // obmc-console-ssh service
3000 if (protocolName == "SSH")
3001 {
3002 getPortNumber(socketPath, [asyncResp, protocolName](
3003 const boost::system::error_code& ec1,
3004 int portNumber) {
3005 if (ec1)
3006 {
3007 BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
3008 messages::internalError(asyncResp->res);
3009 return;
3010 }
3011 nlohmann::json& dataJson1 =
3012 asyncResp->res.jsonValue["SerialConsole"];
3013 dataJson1[protocolName]["Port"] = portNumber;
3014 });
3015 }
3016 }
3017 }
3018
3019 inline void
handleComputerSystemGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3020 handleComputerSystemGet(crow::App& app, const crow::Request& req,
3021 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3022 const std::string& systemName)
3023 {
3024 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3025 {
3026 return;
3027 }
3028
3029 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3030 {
3031 // Option currently returns no systems. TBD
3032 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3033 systemName);
3034 return;
3035 }
3036
3037 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
3038 {
3039 if (systemName == "hypervisor")
3040 {
3041 handleHypervisorSystemGet(asyncResp);
3042 return;
3043 }
3044 }
3045
3046 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3047 {
3048 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3049 systemName);
3050 return;
3051 }
3052 asyncResp->res.addHeader(
3053 boost::beast::http::field::link,
3054 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3055 asyncResp->res.jsonValue["@odata.type"] =
3056 "#ComputerSystem.v1_22_0.ComputerSystem";
3057 asyncResp->res.jsonValue["Name"] = BMCWEB_REDFISH_SYSTEM_URI_NAME;
3058 asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_SYSTEM_URI_NAME;
3059 asyncResp->res.jsonValue["SystemType"] =
3060 computer_system::SystemType::Physical;
3061 asyncResp->res.jsonValue["Description"] = "Computer System";
3062 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
3063 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
3064 double(0);
3065 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
3066 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3067
3068 asyncResp->res.jsonValue["Processors"]["@odata.id"] = boost::urls::format(
3069 "/redfish/v1/Systems/{}/Processors", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3070 asyncResp->res.jsonValue["Memory"]["@odata.id"] = boost::urls::format(
3071 "/redfish/v1/Systems/{}/Memory", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3072 asyncResp->res.jsonValue["Storage"]["@odata.id"] = boost::urls::format(
3073 "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3074 asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] =
3075 boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters",
3076 BMCWEB_REDFISH_SYSTEM_URI_NAME);
3077
3078 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] =
3079 boost::urls::format(
3080 "/redfish/v1/Systems/{}/Actions/ComputerSystem.Reset",
3081 BMCWEB_REDFISH_SYSTEM_URI_NAME);
3082 asyncResp->res
3083 .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] =
3084 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo",
3085 BMCWEB_REDFISH_SYSTEM_URI_NAME);
3086
3087 asyncResp->res.jsonValue["LogServices"]["@odata.id"] = boost::urls::format(
3088 "/redfish/v1/Systems/{}/LogServices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3089 asyncResp->res.jsonValue["Bios"]["@odata.id"] = boost::urls::format(
3090 "/redfish/v1/Systems/{}/Bios", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3091
3092 nlohmann::json::array_t managedBy;
3093 nlohmann::json& manager = managedBy.emplace_back();
3094 manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
3095 BMCWEB_REDFISH_MANAGER_URI_NAME);
3096 asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
3097 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
3098 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
3099
3100 // Fill in SerialConsole info
3101 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
3102 asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true;
3103
3104 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true;
3105 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200;
3106 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
3107 "Press ~. to exit console";
3108 getPortStatusAndPath(std::span{protocolToDBusForSystems},
3109 std::bind_front(afterPortRequest, asyncResp));
3110
3111 if constexpr (BMCWEB_KVM)
3112 {
3113 // Fill in GraphicalConsole info
3114 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
3115 asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] =
3116 4;
3117 asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
3118 nlohmann::json::array_t({"KVMIP"});
3119 }
3120
3121 getMainChassisId(
3122 asyncResp, [](const std::string& chassisId,
3123 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
3124 nlohmann::json::array_t chassisArray;
3125 nlohmann::json& chassis = chassisArray.emplace_back();
3126 chassis["@odata.id"] =
3127 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
3128 aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray);
3129 });
3130
3131 getSystemLocationIndicatorActive(asyncResp);
3132 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
3133 getIndicatorLedState(asyncResp);
3134 getComputerSystem(asyncResp);
3135 getHostState(asyncResp);
3136 getBootProperties(asyncResp);
3137 getBootProgress(asyncResp);
3138 getBootProgressLastStateTime(asyncResp);
3139 pcie_util::getPCIeDeviceList(asyncResp,
3140 nlohmann::json::json_pointer("/PCIeDevices"));
3141 getHostWatchdogTimer(asyncResp);
3142 getPowerRestorePolicy(asyncResp);
3143 getStopBootOnFault(asyncResp);
3144 getAutomaticRetryPolicy(asyncResp);
3145 getLastResetTime(asyncResp);
3146 if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE)
3147 {
3148 getProvisioningStatus(asyncResp);
3149 }
3150 getTrustedModuleRequiredToBoot(asyncResp);
3151 getPowerMode(asyncResp);
3152 getIdlePowerSaver(asyncResp);
3153 }
3154
handleComputerSystemPatch(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3155 inline void handleComputerSystemPatch(
3156 crow::App& app, const crow::Request& req,
3157 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3158 const std::string& systemName)
3159 {
3160 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3161 {
3162 return;
3163 }
3164 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3165 {
3166 // Option currently returns no systems. TBD
3167 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3168 systemName);
3169 return;
3170 }
3171 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3172 {
3173 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3174 systemName);
3175 return;
3176 }
3177
3178 asyncResp->res.addHeader(
3179 boost::beast::http::field::link,
3180 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3181
3182 std::optional<bool> locationIndicatorActive;
3183 std::optional<std::string> indicatorLed;
3184 std::optional<std::string> assetTag;
3185 std::optional<std::string> powerRestorePolicy;
3186 std::optional<std::string> powerMode;
3187 std::optional<bool> wdtEnable;
3188 std::optional<std::string> wdtTimeOutAction;
3189 std::optional<std::string> bootSource;
3190 std::optional<std::string> bootType;
3191 std::optional<std::string> bootEnable;
3192 std::optional<std::string> bootAutomaticRetry;
3193 std::optional<uint32_t> bootAutomaticRetryAttempts;
3194 std::optional<bool> bootTrustedModuleRequired;
3195 std::optional<std::string> stopBootOnFault;
3196 std::optional<bool> ipsEnable;
3197 std::optional<uint8_t> ipsEnterUtil;
3198 std::optional<uint64_t> ipsEnterTime;
3199 std::optional<uint8_t> ipsExitUtil;
3200 std::optional<uint64_t> ipsExitTime;
3201
3202 // clang-format off
3203 if (!json_util::readJsonPatch(
3204 req, asyncResp->res,
3205 "IndicatorLED", indicatorLed,
3206 "LocationIndicatorActive", locationIndicatorActive,
3207 "AssetTag", assetTag,
3208 "PowerRestorePolicy", powerRestorePolicy,
3209 "PowerMode", powerMode,
3210 "HostWatchdogTimer/FunctionEnabled", wdtEnable,
3211 "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,
3212 "Boot/BootSourceOverrideTarget", bootSource,
3213 "Boot/BootSourceOverrideMode", bootType,
3214 "Boot/BootSourceOverrideEnabled", bootEnable,
3215 "Boot/AutomaticRetryConfig", bootAutomaticRetry,
3216 "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts,
3217 "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
3218 "Boot/StopBootOnFault", stopBootOnFault,
3219 "IdlePowerSaver/Enabled", ipsEnable,
3220 "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
3221 "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,
3222 "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,
3223 "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime))
3224 {
3225 return;
3226 }
3227 // clang-format on
3228
3229 asyncResp->res.result(boost::beast::http::status::no_content);
3230
3231 if (assetTag)
3232 {
3233 setAssetTag(asyncResp, *assetTag);
3234 }
3235
3236 if (wdtEnable || wdtTimeOutAction)
3237 {
3238 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3239 }
3240
3241 if (bootSource || bootType || bootEnable)
3242 {
3243 setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3244 }
3245 if (bootAutomaticRetry)
3246 {
3247 setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3248 }
3249
3250 if (bootAutomaticRetryAttempts)
3251 {
3252 setAutomaticRetryAttempts(asyncResp,
3253 bootAutomaticRetryAttempts.value());
3254 }
3255
3256 if (bootTrustedModuleRequired)
3257 {
3258 setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired);
3259 }
3260
3261 if (stopBootOnFault)
3262 {
3263 setStopBootOnFault(asyncResp, *stopBootOnFault);
3264 }
3265
3266 if (locationIndicatorActive)
3267 {
3268 setSystemLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3269 }
3270
3271 // TODO (Gunnar): Remove IndicatorLED after enough time has
3272 // passed
3273 if (indicatorLed)
3274 {
3275 setIndicatorLedState(asyncResp, *indicatorLed);
3276 asyncResp->res.addHeader(boost::beast::http::field::warning,
3277 "299 - \"IndicatorLED is deprecated. Use "
3278 "LocationIndicatorActive instead.\"");
3279 }
3280
3281 if (powerRestorePolicy)
3282 {
3283 setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3284 }
3285
3286 if (powerMode)
3287 {
3288 setPowerMode(asyncResp, *powerMode);
3289 }
3290
3291 if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime)
3292 {
3293 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3294 ipsExitUtil, ipsExitTime);
3295 }
3296 }
3297
handleSystemCollectionResetActionHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)3298 inline void handleSystemCollectionResetActionHead(
3299 crow::App& app, const crow::Request& req,
3300 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3301 const std::string& /*systemName*/)
3302 {
3303 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3304 {
3305 return;
3306 }
3307 asyncResp->res.addHeader(
3308 boost::beast::http::field::link,
3309 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3310 }
3311
3312 /**
3313 * @brief Translates allowed host transitions to redfish string
3314 *
3315 * @param[in] dbusAllowedHostTran The allowed host transition on dbus
3316 * @param[out] allowableValues The translated host transition(s)
3317 *
3318 * @return Emplaces corresponding Redfish translated value(s) in
3319 * allowableValues. If translation not possible, does nothing to
3320 * allowableValues.
3321 */
3322 inline void
dbusToRfAllowedHostTransitions(const std::string & dbusAllowedHostTran,nlohmann::json::array_t & allowableValues)3323 dbusToRfAllowedHostTransitions(const std::string& dbusAllowedHostTran,
3324 nlohmann::json::array_t& allowableValues)
3325 {
3326 if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On")
3327 {
3328 allowableValues.emplace_back(resource::ResetType::On);
3329 allowableValues.emplace_back(resource::ResetType::ForceOn);
3330 }
3331 else if (dbusAllowedHostTran ==
3332 "xyz.openbmc_project.State.Host.Transition.Off")
3333 {
3334 allowableValues.emplace_back(resource::ResetType::GracefulShutdown);
3335 }
3336 else if (dbusAllowedHostTran ==
3337 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
3338 {
3339 allowableValues.emplace_back(resource::ResetType::GracefulRestart);
3340 }
3341 else if (dbusAllowedHostTran ==
3342 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3343 {
3344 allowableValues.emplace_back(resource::ResetType::ForceRestart);
3345 }
3346 else
3347 {
3348 BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran);
3349 }
3350 }
3351
afterGetAllowedHostTransitions(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::vector<std::string> & allowedHostTransitions)3352 inline void afterGetAllowedHostTransitions(
3353 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3354 const boost::system::error_code& ec,
3355 const std::vector<std::string>& allowedHostTransitions)
3356 {
3357 nlohmann::json::array_t allowableValues;
3358
3359 // Supported on all systems currently
3360 allowableValues.emplace_back(resource::ResetType::ForceOff);
3361 allowableValues.emplace_back(resource::ResetType::PowerCycle);
3362 allowableValues.emplace_back(resource::ResetType::Nmi);
3363
3364 if (ec)
3365 {
3366 if ((ec.value() ==
3367 boost::system::linux_error::bad_request_descriptor) ||
3368 (ec.value() == boost::asio::error::basic_errors::host_unreachable))
3369 {
3370 // Property not implemented so just return defaults
3371 BMCWEB_LOG_DEBUG("Property not available {}", ec);
3372 allowableValues.emplace_back(resource::ResetType::On);
3373 allowableValues.emplace_back(resource::ResetType::ForceOn);
3374 allowableValues.emplace_back(resource::ResetType::ForceRestart);
3375 allowableValues.emplace_back(resource::ResetType::GracefulRestart);
3376 allowableValues.emplace_back(resource::ResetType::GracefulShutdown);
3377 }
3378 else
3379 {
3380 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
3381 messages::internalError(asyncResp->res);
3382 return;
3383 }
3384 }
3385 else
3386 {
3387 for (const std::string& transition : allowedHostTransitions)
3388 {
3389 BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition);
3390 dbusToRfAllowedHostTransitions(transition, allowableValues);
3391 }
3392 }
3393
3394 nlohmann::json::object_t parameter;
3395 parameter["Name"] = "ResetType";
3396 parameter["Required"] = true;
3397 parameter["DataType"] = action_info::ParameterTypes::String;
3398 parameter["AllowableValues"] = std::move(allowableValues);
3399 nlohmann::json::array_t parameters;
3400 parameters.emplace_back(std::move(parameter));
3401 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3402 }
3403
handleSystemCollectionResetActionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3404 inline void handleSystemCollectionResetActionGet(
3405 crow::App& app, const crow::Request& req,
3406 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3407 const std::string& systemName)
3408 {
3409 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3410 {
3411 return;
3412 }
3413 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3414 {
3415 // Option currently returns no systems. TBD
3416 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3417 systemName);
3418 return;
3419 }
3420
3421 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
3422 {
3423 if (systemName == "hypervisor")
3424 {
3425 handleHypervisorResetActionGet(asyncResp);
3426 return;
3427 }
3428 }
3429
3430 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3431 {
3432 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3433 systemName);
3434 return;
3435 }
3436
3437 asyncResp->res.addHeader(
3438 boost::beast::http::field::link,
3439 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3440
3441 asyncResp->res.jsonValue["@odata.id"] =
3442 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo",
3443 BMCWEB_REDFISH_SYSTEM_URI_NAME);
3444 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
3445 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3446 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3447
3448 // Look to see if system defines AllowedHostTransitions
3449 sdbusplus::asio::getProperty<std::vector<std::string>>(
3450 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
3451 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host",
3452 "AllowedHostTransitions",
3453 [asyncResp](const boost::system::error_code& ec,
3454 const std::vector<std::string>& allowedHostTransitions) {
3455 afterGetAllowedHostTransitions(asyncResp, ec,
3456 allowedHostTransitions);
3457 });
3458 }
3459 /**
3460 * SystemResetActionInfo derived class for delivering Computer Systems
3461 * ResetType AllowableValues using ResetInfo schema.
3462 */
requestRoutesSystems(App & app)3463 inline void requestRoutesSystems(App& app)
3464 {
3465 BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
3466 .privileges(redfish::privileges::headComputerSystemCollection)
3467 .methods(boost::beast::http::verb::head)(
3468 std::bind_front(handleComputerSystemCollectionHead, std::ref(app)));
3469
3470 BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
3471 .privileges(redfish::privileges::getComputerSystemCollection)
3472 .methods(boost::beast::http::verb::get)(
3473 std::bind_front(handleComputerSystemCollectionGet, std::ref(app)));
3474
3475 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3476 .privileges(redfish::privileges::headComputerSystem)
3477 .methods(boost::beast::http::verb::head)(
3478 std::bind_front(handleComputerSystemHead, std::ref(app)));
3479
3480 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3481 .privileges(redfish::privileges::getComputerSystem)
3482 .methods(boost::beast::http::verb::get)(
3483 std::bind_front(handleComputerSystemGet, std::ref(app)));
3484
3485 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3486 .privileges(redfish::privileges::patchComputerSystem)
3487 .methods(boost::beast::http::verb::patch)(
3488 std::bind_front(handleComputerSystemPatch, std::ref(app)));
3489
3490 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/")
3491 .privileges(redfish::privileges::postComputerSystem)
3492 .methods(boost::beast::http::verb::post)(std::bind_front(
3493 handleComputerSystemResetActionPost, std::ref(app)));
3494
3495 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3496 .privileges(redfish::privileges::headActionInfo)
3497 .methods(boost::beast::http::verb::head)(std::bind_front(
3498 handleSystemCollectionResetActionHead, std::ref(app)));
3499 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3500 .privileges(redfish::privileges::getActionInfo)
3501 .methods(boost::beast::http::verb::get)(std::bind_front(
3502 handleSystemCollectionResetActionGet, std::ref(app)));
3503 }
3504 } // namespace redfish
3505