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