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