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