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