xref: /openbmc/bmcweb/features/redfish/include/redfish_aggregator.hpp (revision 002d39b4a7a5ed7166e2acad84e0943c3def9492)
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