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