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