17fb33566SCarson Labrado #pragma once 27fb33566SCarson Labrado 37fb33566SCarson Labrado #include <http_client.hpp> 47fb33566SCarson Labrado 57fb33566SCarson Labrado namespace redfish 67fb33566SCarson Labrado { 77fb33566SCarson Labrado 87fb33566SCarson Labrado class RedfishAggregator 97fb33566SCarson Labrado { 107fb33566SCarson Labrado private: 117fb33566SCarson Labrado RedfishAggregator() 127fb33566SCarson Labrado { 137fb33566SCarson Labrado getSatelliteConfigs(constructorCallback); 147fb33566SCarson Labrado } 157fb33566SCarson Labrado 167fb33566SCarson Labrado // Dummy callback used by the Constructor so that it can report the number 177fb33566SCarson Labrado // of satellite configs when the class is first created 187fb33566SCarson Labrado static void constructorCallback( 197fb33566SCarson Labrado const std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 207fb33566SCarson Labrado { 217fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "There were " 227fb33566SCarson Labrado << std::to_string(satelliteInfo.size()) 237fb33566SCarson Labrado << " satellite configs found at startup"; 247fb33566SCarson Labrado } 257fb33566SCarson Labrado 267fb33566SCarson Labrado // Polls D-Bus to get all available satellite config information 277fb33566SCarson Labrado // Expects a handler which interacts with the returned configs 287fb33566SCarson Labrado static void getSatelliteConfigs( 297fb33566SCarson Labrado const std::function<void( 307fb33566SCarson Labrado const std::unordered_map<std::string, boost::urls::url>&)>& handler) 317fb33566SCarson Labrado { 327fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "Gathering satellite configs"; 337fb33566SCarson Labrado crow::connections::systemBus->async_method_call( 347fb33566SCarson Labrado [handler](const boost::system::error_code ec, 357fb33566SCarson Labrado const dbus::utility::ManagedObjectType& objects) { 367fb33566SCarson Labrado if (ec) 377fb33566SCarson Labrado { 38*002d39b4SEd Tanous BMCWEB_LOG_ERROR << "DBUS response error " << ec.value() << ", " 39*002d39b4SEd Tanous << ec.message(); 407fb33566SCarson Labrado return; 417fb33566SCarson Labrado } 427fb33566SCarson Labrado 437fb33566SCarson Labrado // Maps a chosen alias representing a satellite BMC to a url 447fb33566SCarson Labrado // containing the information required to create a http 457fb33566SCarson Labrado // connection to the satellite 467fb33566SCarson Labrado std::unordered_map<std::string, boost::urls::url> satelliteInfo; 477fb33566SCarson Labrado 487fb33566SCarson Labrado findSatelliteConfigs(objects, satelliteInfo); 497fb33566SCarson Labrado 507fb33566SCarson Labrado if (!satelliteInfo.empty()) 517fb33566SCarson Labrado { 527fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "Redfish Aggregation enabled with " 537fb33566SCarson Labrado << std::to_string(satelliteInfo.size()) 547fb33566SCarson Labrado << " satellite BMCs"; 557fb33566SCarson Labrado } 567fb33566SCarson Labrado else 577fb33566SCarson Labrado { 587fb33566SCarson Labrado BMCWEB_LOG_DEBUG 597fb33566SCarson Labrado << "No satellite BMCs detected. Redfish Aggregation not enabled"; 607fb33566SCarson Labrado } 617fb33566SCarson Labrado handler(satelliteInfo); 627fb33566SCarson Labrado }, 637fb33566SCarson Labrado "xyz.openbmc_project.EntityManager", "/", 647fb33566SCarson Labrado "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 657fb33566SCarson Labrado } 667fb33566SCarson Labrado 677fb33566SCarson Labrado // Search D-Bus objects for satellite config objects and add their 687fb33566SCarson Labrado // information if valid 697fb33566SCarson Labrado static void findSatelliteConfigs( 707fb33566SCarson Labrado const dbus::utility::ManagedObjectType& objects, 717fb33566SCarson Labrado std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 727fb33566SCarson Labrado { 737fb33566SCarson Labrado for (const auto& objectPath : objects) 747fb33566SCarson Labrado { 757fb33566SCarson Labrado for (const auto& interface : objectPath.second) 767fb33566SCarson Labrado { 777fb33566SCarson Labrado if (interface.first == 787fb33566SCarson Labrado "xyz.openbmc_project.Configuration.SatelliteController") 797fb33566SCarson Labrado { 807fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "Found Satellite Controller at " 817fb33566SCarson Labrado << objectPath.first.str; 827fb33566SCarson Labrado 837fb33566SCarson Labrado addSatelliteConfig(interface.second, satelliteInfo); 847fb33566SCarson Labrado } 857fb33566SCarson Labrado } 867fb33566SCarson Labrado } 877fb33566SCarson Labrado } 887fb33566SCarson Labrado 897fb33566SCarson Labrado // Parse the properties of a satellite config object and add the 907fb33566SCarson Labrado // configuration if the properties are valid 917fb33566SCarson Labrado static void addSatelliteConfig( 927fb33566SCarson Labrado const dbus::utility::DBusPropertiesMap& properties, 937fb33566SCarson Labrado std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 947fb33566SCarson Labrado { 957fb33566SCarson Labrado boost::urls::url url; 967fb33566SCarson Labrado std::string name; 977fb33566SCarson Labrado 987fb33566SCarson Labrado for (const auto& prop : properties) 997fb33566SCarson Labrado { 1007fb33566SCarson Labrado if (prop.first == "Name") 1017fb33566SCarson Labrado { 1027fb33566SCarson Labrado const std::string* propVal = 1037fb33566SCarson Labrado std::get_if<std::string>(&prop.second); 1047fb33566SCarson Labrado if (propVal == nullptr) 1057fb33566SCarson Labrado { 1067fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid Name value"; 1077fb33566SCarson Labrado return; 1087fb33566SCarson Labrado } 1097fb33566SCarson Labrado 1107fb33566SCarson Labrado // The IDs will become <Name>_<ID> so the name should not 1117fb33566SCarson Labrado // contain a '_' 1127fb33566SCarson Labrado if (propVal->find('_') != std::string::npos) 1137fb33566SCarson Labrado { 1147fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Name cannot contain a \"_\""; 1157fb33566SCarson Labrado return; 1167fb33566SCarson Labrado } 1177fb33566SCarson Labrado name = *propVal; 1187fb33566SCarson Labrado } 1197fb33566SCarson Labrado 1207fb33566SCarson Labrado else if (prop.first == "Hostname") 1217fb33566SCarson Labrado { 1227fb33566SCarson Labrado const std::string* propVal = 1237fb33566SCarson Labrado std::get_if<std::string>(&prop.second); 1247fb33566SCarson Labrado if (propVal == nullptr) 1257fb33566SCarson Labrado { 1267fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid Hostname value"; 1277fb33566SCarson Labrado return; 1287fb33566SCarson Labrado } 1297fb33566SCarson Labrado url.set_host(*propVal); 1307fb33566SCarson Labrado } 1317fb33566SCarson Labrado 1327fb33566SCarson Labrado else if (prop.first == "Port") 1337fb33566SCarson Labrado { 1347fb33566SCarson Labrado const uint64_t* propVal = std::get_if<uint64_t>(&prop.second); 1357fb33566SCarson Labrado if (propVal == nullptr) 1367fb33566SCarson Labrado { 1377fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid Port value"; 1387fb33566SCarson Labrado return; 1397fb33566SCarson Labrado } 1407fb33566SCarson Labrado 1417fb33566SCarson Labrado if (*propVal > std::numeric_limits<uint16_t>::max()) 1427fb33566SCarson Labrado { 1437fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Port value out of range"; 1447fb33566SCarson Labrado return; 1457fb33566SCarson Labrado } 1467fb33566SCarson Labrado url.set_port(static_cast<uint16_t>(*propVal)); 1477fb33566SCarson Labrado } 1487fb33566SCarson Labrado 1497fb33566SCarson Labrado else if (prop.first == "AuthType") 1507fb33566SCarson Labrado { 1517fb33566SCarson Labrado const std::string* propVal = 1527fb33566SCarson Labrado std::get_if<std::string>(&prop.second); 1537fb33566SCarson Labrado if (propVal == nullptr) 1547fb33566SCarson Labrado { 1557fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid AuthType value"; 1567fb33566SCarson Labrado return; 1577fb33566SCarson Labrado } 1587fb33566SCarson Labrado 1597fb33566SCarson Labrado // For now assume authentication not required to communicate 1607fb33566SCarson Labrado // with the satellite BMC 1617fb33566SCarson Labrado if (*propVal != "None") 1627fb33566SCarson Labrado { 1637fb33566SCarson Labrado BMCWEB_LOG_ERROR 1647fb33566SCarson Labrado << "Unsupported AuthType value: " << *propVal 1657fb33566SCarson Labrado << ", only \"none\" is supported"; 1667fb33566SCarson Labrado return; 1677fb33566SCarson Labrado } 1687fb33566SCarson Labrado url.set_scheme("http"); 1697fb33566SCarson Labrado } 1707fb33566SCarson Labrado } // Finished reading properties 1717fb33566SCarson Labrado 1727fb33566SCarson Labrado // Make sure all required config information was made available 1737fb33566SCarson Labrado if (name.empty()) 1747fb33566SCarson Labrado { 1757fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config missing Name"; 1767fb33566SCarson Labrado return; 1777fb33566SCarson Labrado } 1787fb33566SCarson Labrado 1797fb33566SCarson Labrado if (url.host().empty()) 1807fb33566SCarson Labrado { 1817fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config " << name << " missing Host"; 1827fb33566SCarson Labrado return; 1837fb33566SCarson Labrado } 1847fb33566SCarson Labrado 1857fb33566SCarson Labrado if (!url.has_port()) 1867fb33566SCarson Labrado { 1877fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config " << name << " missing Port"; 1887fb33566SCarson Labrado return; 1897fb33566SCarson Labrado } 1907fb33566SCarson Labrado 1917fb33566SCarson Labrado if (!url.has_scheme()) 1927fb33566SCarson Labrado { 1937fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config " << name 1947fb33566SCarson Labrado << " missing AuthType"; 1957fb33566SCarson Labrado return; 1967fb33566SCarson Labrado } 1977fb33566SCarson Labrado 1987fb33566SCarson Labrado std::string resultString; 1997fb33566SCarson Labrado auto result = satelliteInfo.insert_or_assign(name, std::move(url)); 2007fb33566SCarson Labrado if (result.second) 2017fb33566SCarson Labrado { 2027fb33566SCarson Labrado resultString = "Added new satellite config "; 2037fb33566SCarson Labrado } 2047fb33566SCarson Labrado else 2057fb33566SCarson Labrado { 2067fb33566SCarson Labrado resultString = "Updated existing satellite config "; 2077fb33566SCarson Labrado } 2087fb33566SCarson Labrado 2097fb33566SCarson Labrado BMCWEB_LOG_DEBUG << resultString << name << " at " 2107fb33566SCarson Labrado << result.first->second.scheme() << "://" 2117fb33566SCarson Labrado << result.first->second.encoded_host_and_port(); 2127fb33566SCarson Labrado } 2137fb33566SCarson Labrado 2147fb33566SCarson Labrado public: 2157fb33566SCarson Labrado RedfishAggregator(const RedfishAggregator&) = delete; 2167fb33566SCarson Labrado RedfishAggregator& operator=(const RedfishAggregator&) = delete; 2177fb33566SCarson Labrado RedfishAggregator(RedfishAggregator&&) = delete; 2187fb33566SCarson Labrado RedfishAggregator& operator=(RedfishAggregator&&) = delete; 2197fb33566SCarson Labrado ~RedfishAggregator() = default; 2207fb33566SCarson Labrado 2217fb33566SCarson Labrado static RedfishAggregator& getInstance() 2227fb33566SCarson Labrado { 2237fb33566SCarson Labrado static RedfishAggregator handler; 2247fb33566SCarson Labrado return handler; 2257fb33566SCarson Labrado } 2267fb33566SCarson Labrado }; 2277fb33566SCarson Labrado 2287fb33566SCarson Labrado } // namespace redfish 229