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