11bb1a50fSOliver Brewka // SPDX-License-Identifier: Apache-2.0 21bb1a50fSOliver Brewka // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3fc5ae94dSOliver Brewka #pragma once 4fc5ae94dSOliver Brewka 5fc5ae94dSOliver Brewka #include "bmcweb_config.h" 6fc5ae94dSOliver Brewka 7fc5ae94dSOliver Brewka #include "async_resp.hpp" 8*2fdbc1f3SOliver Brewka #include "dbus_singleton.hpp" 9fc5ae94dSOliver Brewka #include "dbus_utility.hpp" 10fc5ae94dSOliver Brewka #include "error_messages.hpp" 11fc5ae94dSOliver Brewka #include "human_sort.hpp" 12fc5ae94dSOliver Brewka #include "logging.hpp" 13fc5ae94dSOliver Brewka #include "utility.hpp" 14fc5ae94dSOliver Brewka 15fc5ae94dSOliver Brewka #include <boost/url/format.hpp> 16fc5ae94dSOliver Brewka #include <boost/url/url.hpp> 17fc5ae94dSOliver Brewka #include <sdbusplus/message/native_types.hpp> 18fc5ae94dSOliver Brewka 19fc5ae94dSOliver Brewka #include <algorithm> 20fc5ae94dSOliver Brewka #include <array> 21*2fdbc1f3SOliver Brewka #include <cstdint> 22fc5ae94dSOliver Brewka #include <functional> 23fc5ae94dSOliver Brewka #include <memory> 24fc5ae94dSOliver Brewka #include <string> 25fc5ae94dSOliver Brewka #include <string_view> 26fc5ae94dSOliver Brewka #include <utility> 27fc5ae94dSOliver Brewka #include <vector> 28fc5ae94dSOliver Brewka 29fc5ae94dSOliver Brewka namespace redfish 30fc5ae94dSOliver Brewka { 31fc5ae94dSOliver Brewka 32fc5ae94dSOliver Brewka inline void handleSystemCollectionMembers( 33fc5ae94dSOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 34fc5ae94dSOliver Brewka const boost::system::error_code& ec, 35fc5ae94dSOliver Brewka const dbus::utility::MapperGetSubTreePathsResponse& objects) 36fc5ae94dSOliver Brewka { 37fc5ae94dSOliver Brewka if (ec == boost::system::errc::io_error) 38fc5ae94dSOliver Brewka { 39fc5ae94dSOliver Brewka asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 40fc5ae94dSOliver Brewka asyncResp->res.jsonValue["Members@odata.count"] = 0; 41fc5ae94dSOliver Brewka return; 42fc5ae94dSOliver Brewka } 43fc5ae94dSOliver Brewka 44fc5ae94dSOliver Brewka if (ec) 45fc5ae94dSOliver Brewka { 46fc5ae94dSOliver Brewka BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 47fc5ae94dSOliver Brewka messages::internalError(asyncResp->res); 48fc5ae94dSOliver Brewka return; 49fc5ae94dSOliver Brewka } 50fc5ae94dSOliver Brewka 51fc5ae94dSOliver Brewka nlohmann::json& membersArray = asyncResp->res.jsonValue["Members"]; 52fc5ae94dSOliver Brewka membersArray = nlohmann::json::array(); 53fc5ae94dSOliver Brewka 54fc5ae94dSOliver Brewka // consider an empty result as single-host, since single-host systems 55fc5ae94dSOliver Brewka // do not populate the ManagedHost dbus interface 56fc5ae94dSOliver Brewka if (objects.empty()) 57fc5ae94dSOliver Brewka { 58fc5ae94dSOliver Brewka asyncResp->res.jsonValue["Members@odata.count"] = 1; 59fc5ae94dSOliver Brewka nlohmann::json::object_t system; 60fc5ae94dSOliver Brewka system["@odata.id"] = boost::urls::format( 61fc5ae94dSOliver Brewka "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 62fc5ae94dSOliver Brewka membersArray.emplace_back(std::move(system)); 63fc5ae94dSOliver Brewka 64fc5ae94dSOliver Brewka if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 65fc5ae94dSOliver Brewka { 66fc5ae94dSOliver Brewka BMCWEB_LOG_DEBUG("Hypervisor is available"); 67fc5ae94dSOliver Brewka asyncResp->res.jsonValue["Members@odata.count"] = 2; 68fc5ae94dSOliver Brewka 69fc5ae94dSOliver Brewka nlohmann::json::object_t hypervisor; 70fc5ae94dSOliver Brewka hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor"; 71fc5ae94dSOliver Brewka membersArray.emplace_back(std::move(hypervisor)); 72fc5ae94dSOliver Brewka } 73fc5ae94dSOliver Brewka 74fc5ae94dSOliver Brewka return; 75fc5ae94dSOliver Brewka } 76fc5ae94dSOliver Brewka 77fc5ae94dSOliver Brewka std::vector<std::string> pathNames; 78fc5ae94dSOliver Brewka for (const auto& object : objects) 79fc5ae94dSOliver Brewka { 80fc5ae94dSOliver Brewka sdbusplus::message::object_path path(object); 81fc5ae94dSOliver Brewka std::string leaf = path.filename(); 82fc5ae94dSOliver Brewka if (leaf.empty()) 83fc5ae94dSOliver Brewka { 84fc5ae94dSOliver Brewka continue; 85fc5ae94dSOliver Brewka } 86fc5ae94dSOliver Brewka pathNames.emplace_back(leaf); 87fc5ae94dSOliver Brewka } 88fc5ae94dSOliver Brewka std::ranges::sort(pathNames, AlphanumLess<std::string>()); 89fc5ae94dSOliver Brewka 90fc5ae94dSOliver Brewka for (const std::string& systemName : pathNames) 91fc5ae94dSOliver Brewka { 92fc5ae94dSOliver Brewka nlohmann::json::object_t member; 936b90272cSOliver Brewka member["@odata.id"] = 946b90272cSOliver Brewka boost::urls::format("/redfish/v1/Systems/{}", systemName); 95fc5ae94dSOliver Brewka membersArray.emplace_back(std::move(member)); 96fc5ae94dSOliver Brewka } 97fc5ae94dSOliver Brewka asyncResp->res.jsonValue["Members@odata.count"] = membersArray.size(); 98fc5ae94dSOliver Brewka } 99fc5ae94dSOliver Brewka 100fc5ae94dSOliver Brewka /** 101fc5ae94dSOliver Brewka * @brief Populate the system collection members from a GetSubTreePaths search 102fc5ae94dSOliver Brewka * of the inventory based of the ManagedHost dbus interface 103fc5ae94dSOliver Brewka * 104fc5ae94dSOliver Brewka * @param[i] asyncResp Async response object 105fc5ae94dSOliver Brewka * 106fc5ae94dSOliver Brewka * @return None 107fc5ae94dSOliver Brewka */ 108fc5ae94dSOliver Brewka inline void getSystemCollectionMembers( 109fc5ae94dSOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 110fc5ae94dSOliver Brewka { 111fc5ae94dSOliver Brewka constexpr std::array<std::string_view, 1> interfaces{ 112fc5ae94dSOliver Brewka "xyz.openbmc_project.Inventory.Decorator.ManagedHost", 113fc5ae94dSOliver Brewka }; 114fc5ae94dSOliver Brewka 115fc5ae94dSOliver Brewka BMCWEB_LOG_DEBUG("Get system collection members for /redfish/v1/Systems"); 116fc5ae94dSOliver Brewka 117fc5ae94dSOliver Brewka dbus::utility::getSubTreePaths( 118fc5ae94dSOliver Brewka "/xyz/openbmc_project/inventory", 0, interfaces, 119fc5ae94dSOliver Brewka std::bind_front(handleSystemCollectionMembers, asyncResp)); 120fc5ae94dSOliver Brewka } 121*2fdbc1f3SOliver Brewka 122*2fdbc1f3SOliver Brewka inline void getManagedHostProperty( 123*2fdbc1f3SOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 124*2fdbc1f3SOliver Brewka const std::string& systemName, const std::string& systemPath, 125*2fdbc1f3SOliver Brewka std::function<void(const uint64_t computerSystemIndex)> callback) 126*2fdbc1f3SOliver Brewka { 127*2fdbc1f3SOliver Brewka dbus::utility::getProperty<uint64_t>( 128*2fdbc1f3SOliver Brewka "xyz.openbmc_project.EntityManager", systemPath, 129*2fdbc1f3SOliver Brewka "xyz.openbmc_project.Inventory.Decorator.ManagedHost", "HostIndex", 130*2fdbc1f3SOliver Brewka [asyncResp, systemName, systemPath, callback = std::move(callback)]( 131*2fdbc1f3SOliver Brewka const boost::system::error_code& ec, const uint64_t hostIndex) { 132*2fdbc1f3SOliver Brewka if (ec) 133*2fdbc1f3SOliver Brewka { 134*2fdbc1f3SOliver Brewka BMCWEB_LOG_WARNING("DBUS response error {}", ec); 135*2fdbc1f3SOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem", 136*2fdbc1f3SOliver Brewka systemName); 137*2fdbc1f3SOliver Brewka return; 138*2fdbc1f3SOliver Brewka } 139*2fdbc1f3SOliver Brewka BMCWEB_LOG_DEBUG("Got index {} for path {}", hostIndex, systemPath); 140*2fdbc1f3SOliver Brewka callback(hostIndex); 141*2fdbc1f3SOliver Brewka }); 142*2fdbc1f3SOliver Brewka } 143*2fdbc1f3SOliver Brewka 144*2fdbc1f3SOliver Brewka inline void afterGetComputerSystemSubTreePaths( 145*2fdbc1f3SOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 146*2fdbc1f3SOliver Brewka const std::string& systemName, 147*2fdbc1f3SOliver Brewka std::function<void(const uint64_t computerSystemIndex)>& callback, 148*2fdbc1f3SOliver Brewka const boost::system::error_code& ec, 149*2fdbc1f3SOliver Brewka const dbus::utility::MapperGetSubTreePathsResponse& objects) 150*2fdbc1f3SOliver Brewka { 151*2fdbc1f3SOliver Brewka sdbusplus::message::object_path systemPath; 152*2fdbc1f3SOliver Brewka if (ec) 153*2fdbc1f3SOliver Brewka { 154*2fdbc1f3SOliver Brewka if (ec.value() == boost::system::errc::io_error) 155*2fdbc1f3SOliver Brewka { 156*2fdbc1f3SOliver Brewka BMCWEB_LOG_WARNING("EIO - System not found"); 157*2fdbc1f3SOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem", 158*2fdbc1f3SOliver Brewka systemName); 159*2fdbc1f3SOliver Brewka return; 160*2fdbc1f3SOliver Brewka } 161*2fdbc1f3SOliver Brewka 162*2fdbc1f3SOliver Brewka BMCWEB_LOG_ERROR("DBus method call failed with error {}", ec.value()); 163*2fdbc1f3SOliver Brewka messages::internalError(asyncResp->res); 164*2fdbc1f3SOliver Brewka return; 165*2fdbc1f3SOliver Brewka } 166*2fdbc1f3SOliver Brewka 167*2fdbc1f3SOliver Brewka const auto& found = std::ranges::find_if( 168*2fdbc1f3SOliver Brewka objects, [systemName](const sdbusplus::message::object_path& path) { 169*2fdbc1f3SOliver Brewka return path.filename() == systemName; 170*2fdbc1f3SOliver Brewka }); 171*2fdbc1f3SOliver Brewka 172*2fdbc1f3SOliver Brewka if (found == objects.end()) 173*2fdbc1f3SOliver Brewka { 174*2fdbc1f3SOliver Brewka BMCWEB_LOG_WARNING("Failed to match systemName: {}", systemName); 175*2fdbc1f3SOliver Brewka messages::resourceNotFound(asyncResp->res, "ComputerSystem", 176*2fdbc1f3SOliver Brewka systemName); 177*2fdbc1f3SOliver Brewka return; 178*2fdbc1f3SOliver Brewka } 179*2fdbc1f3SOliver Brewka 180*2fdbc1f3SOliver Brewka systemPath = *found; 181*2fdbc1f3SOliver Brewka 182*2fdbc1f3SOliver Brewka getManagedHostProperty(asyncResp, systemName, systemPath, 183*2fdbc1f3SOliver Brewka std::move(callback)); 184*2fdbc1f3SOliver Brewka } 185*2fdbc1f3SOliver Brewka 186*2fdbc1f3SOliver Brewka /** 187*2fdbc1f3SOliver Brewka * @brief Retrieve the index associated with the requested system based on the 188*2fdbc1f3SOliver Brewka * ManagedHost interface 189*2fdbc1f3SOliver Brewka * 190*2fdbc1f3SOliver Brewka * @param[i] asyncResp Async response object 191*2fdbc1f3SOliver Brewka * @param[i] systemName The requested system 192*2fdbc1f3SOliver Brewka * @param[i] callback Callback to call once the index has been found 193*2fdbc1f3SOliver Brewka * 194*2fdbc1f3SOliver Brewka * @return None 195*2fdbc1f3SOliver Brewka */ 196*2fdbc1f3SOliver Brewka inline void getComputerSystemIndex( 197*2fdbc1f3SOliver Brewka const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 198*2fdbc1f3SOliver Brewka const std::string& systemName, 199*2fdbc1f3SOliver Brewka std::function<void(const uint64_t computerSystemIndex)>&& callback) 200*2fdbc1f3SOliver Brewka { 201*2fdbc1f3SOliver Brewka if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 202*2fdbc1f3SOliver Brewka { 203*2fdbc1f3SOliver Brewka constexpr std::array<std::string_view, 1> interfaces{ 204*2fdbc1f3SOliver Brewka "xyz.openbmc_project.Inventory.Decorator.ManagedHost"}; 205*2fdbc1f3SOliver Brewka dbus::utility::getSubTreePaths( 206*2fdbc1f3SOliver Brewka "/xyz/openbmc_project/inventory", 0, interfaces, 207*2fdbc1f3SOliver Brewka std::bind_front(afterGetComputerSystemSubTreePaths, asyncResp, 208*2fdbc1f3SOliver Brewka systemName, std::move(callback))); 209*2fdbc1f3SOliver Brewka } 210*2fdbc1f3SOliver Brewka else 211*2fdbc1f3SOliver Brewka { 212*2fdbc1f3SOliver Brewka // on single-host, fallback to index 0 213*2fdbc1f3SOliver Brewka BMCWEB_LOG_DEBUG( 214*2fdbc1f3SOliver Brewka "Single-host detected, fallback to computerSystemIndex 0"); 215*2fdbc1f3SOliver Brewka callback(0); 216*2fdbc1f3SOliver Brewka } 217*2fdbc1f3SOliver Brewka } 218*2fdbc1f3SOliver Brewka 219*2fdbc1f3SOliver Brewka inline sdbusplus::message::object_path getHostStateObjectPath( 220*2fdbc1f3SOliver Brewka const uint64_t computerSystemIndex) 221*2fdbc1f3SOliver Brewka { 222*2fdbc1f3SOliver Brewka const sdbusplus::message::object_path hostStatePath( 223*2fdbc1f3SOliver Brewka "/xyz/openbmc_project/state/host" + 224*2fdbc1f3SOliver Brewka std::to_string(computerSystemIndex)); 225*2fdbc1f3SOliver Brewka 226*2fdbc1f3SOliver Brewka return hostStatePath; 227*2fdbc1f3SOliver Brewka } 228*2fdbc1f3SOliver Brewka 229*2fdbc1f3SOliver Brewka inline std::string getHostStateServiceName(const uint64_t computerSystemIndex) 230*2fdbc1f3SOliver Brewka { 231*2fdbc1f3SOliver Brewka std::string hostStateService = "xyz.openbmc_project.State.Host"; 232*2fdbc1f3SOliver Brewka if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 233*2fdbc1f3SOliver Brewka { 234*2fdbc1f3SOliver Brewka hostStateService += std::to_string(computerSystemIndex); 235*2fdbc1f3SOliver Brewka } 236*2fdbc1f3SOliver Brewka 237*2fdbc1f3SOliver Brewka return hostStateService; 238*2fdbc1f3SOliver Brewka } 239*2fdbc1f3SOliver Brewka 240*2fdbc1f3SOliver Brewka inline sdbusplus::message::object_path getChassisStateObjectPath( 241*2fdbc1f3SOliver Brewka const uint64_t computerSystemIndex) 242*2fdbc1f3SOliver Brewka { 243*2fdbc1f3SOliver Brewka const sdbusplus::message::object_path chassisStatePath( 244*2fdbc1f3SOliver Brewka "/xyz/openbmc_project/state/chassis" + 245*2fdbc1f3SOliver Brewka std::to_string(computerSystemIndex)); 246*2fdbc1f3SOliver Brewka 247*2fdbc1f3SOliver Brewka return chassisStatePath; 248*2fdbc1f3SOliver Brewka } 249*2fdbc1f3SOliver Brewka 250*2fdbc1f3SOliver Brewka inline std::string getChassisStateServiceName( 251*2fdbc1f3SOliver Brewka const uint64_t computerSystemIndex) 252*2fdbc1f3SOliver Brewka { 253*2fdbc1f3SOliver Brewka std::string chassisStateService = "xyz.openbmc_project.State.Chassis"; 254*2fdbc1f3SOliver Brewka if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 255*2fdbc1f3SOliver Brewka { 256*2fdbc1f3SOliver Brewka chassisStateService += std::to_string(computerSystemIndex); 257*2fdbc1f3SOliver Brewka } 258*2fdbc1f3SOliver Brewka 259*2fdbc1f3SOliver Brewka return chassisStateService; 260*2fdbc1f3SOliver Brewka } 261fc5ae94dSOliver Brewka } // namespace redfish 262