1*7fb33566SCarson Labrado #pragma once 2*7fb33566SCarson Labrado 3*7fb33566SCarson Labrado #include <http_client.hpp> 4*7fb33566SCarson Labrado 5*7fb33566SCarson Labrado namespace redfish 6*7fb33566SCarson Labrado { 7*7fb33566SCarson Labrado 8*7fb33566SCarson Labrado class RedfishAggregator 9*7fb33566SCarson Labrado { 10*7fb33566SCarson Labrado private: 11*7fb33566SCarson Labrado RedfishAggregator() 12*7fb33566SCarson Labrado { 13*7fb33566SCarson Labrado getSatelliteConfigs(constructorCallback); 14*7fb33566SCarson Labrado } 15*7fb33566SCarson Labrado 16*7fb33566SCarson Labrado // Dummy callback used by the Constructor so that it can report the number 17*7fb33566SCarson Labrado // of satellite configs when the class is first created 18*7fb33566SCarson Labrado static void constructorCallback( 19*7fb33566SCarson Labrado const std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 20*7fb33566SCarson Labrado { 21*7fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "There were " 22*7fb33566SCarson Labrado << std::to_string(satelliteInfo.size()) 23*7fb33566SCarson Labrado << " satellite configs found at startup"; 24*7fb33566SCarson Labrado } 25*7fb33566SCarson Labrado 26*7fb33566SCarson Labrado // Polls D-Bus to get all available satellite config information 27*7fb33566SCarson Labrado // Expects a handler which interacts with the returned configs 28*7fb33566SCarson Labrado static void getSatelliteConfigs( 29*7fb33566SCarson Labrado const std::function<void( 30*7fb33566SCarson Labrado const std::unordered_map<std::string, boost::urls::url>&)>& handler) 31*7fb33566SCarson Labrado { 32*7fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "Gathering satellite configs"; 33*7fb33566SCarson Labrado crow::connections::systemBus->async_method_call( 34*7fb33566SCarson Labrado [handler](const boost::system::error_code ec, 35*7fb33566SCarson Labrado const dbus::utility::ManagedObjectType& objects) { 36*7fb33566SCarson Labrado if (ec) 37*7fb33566SCarson Labrado { 38*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "DBUS response error " << ec.value() 39*7fb33566SCarson Labrado << ", " << ec.message(); 40*7fb33566SCarson Labrado return; 41*7fb33566SCarson Labrado } 42*7fb33566SCarson Labrado 43*7fb33566SCarson Labrado // Maps a chosen alias representing a satellite BMC to a url 44*7fb33566SCarson Labrado // containing the information required to create a http 45*7fb33566SCarson Labrado // connection to the satellite 46*7fb33566SCarson Labrado std::unordered_map<std::string, boost::urls::url> satelliteInfo; 47*7fb33566SCarson Labrado 48*7fb33566SCarson Labrado findSatelliteConfigs(objects, satelliteInfo); 49*7fb33566SCarson Labrado 50*7fb33566SCarson Labrado if (!satelliteInfo.empty()) 51*7fb33566SCarson Labrado { 52*7fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "Redfish Aggregation enabled with " 53*7fb33566SCarson Labrado << std::to_string(satelliteInfo.size()) 54*7fb33566SCarson Labrado << " satellite BMCs"; 55*7fb33566SCarson Labrado } 56*7fb33566SCarson Labrado else 57*7fb33566SCarson Labrado { 58*7fb33566SCarson Labrado BMCWEB_LOG_DEBUG 59*7fb33566SCarson Labrado << "No satellite BMCs detected. Redfish Aggregation not enabled"; 60*7fb33566SCarson Labrado } 61*7fb33566SCarson Labrado handler(satelliteInfo); 62*7fb33566SCarson Labrado }, 63*7fb33566SCarson Labrado "xyz.openbmc_project.EntityManager", "/", 64*7fb33566SCarson Labrado "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 65*7fb33566SCarson Labrado } 66*7fb33566SCarson Labrado 67*7fb33566SCarson Labrado // Search D-Bus objects for satellite config objects and add their 68*7fb33566SCarson Labrado // information if valid 69*7fb33566SCarson Labrado static void findSatelliteConfigs( 70*7fb33566SCarson Labrado const dbus::utility::ManagedObjectType& objects, 71*7fb33566SCarson Labrado std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 72*7fb33566SCarson Labrado { 73*7fb33566SCarson Labrado for (const auto& objectPath : objects) 74*7fb33566SCarson Labrado { 75*7fb33566SCarson Labrado for (const auto& interface : objectPath.second) 76*7fb33566SCarson Labrado { 77*7fb33566SCarson Labrado if (interface.first == 78*7fb33566SCarson Labrado "xyz.openbmc_project.Configuration.SatelliteController") 79*7fb33566SCarson Labrado { 80*7fb33566SCarson Labrado BMCWEB_LOG_DEBUG << "Found Satellite Controller at " 81*7fb33566SCarson Labrado << objectPath.first.str; 82*7fb33566SCarson Labrado 83*7fb33566SCarson Labrado addSatelliteConfig(interface.second, satelliteInfo); 84*7fb33566SCarson Labrado } 85*7fb33566SCarson Labrado } 86*7fb33566SCarson Labrado } 87*7fb33566SCarson Labrado } 88*7fb33566SCarson Labrado 89*7fb33566SCarson Labrado // Parse the properties of a satellite config object and add the 90*7fb33566SCarson Labrado // configuration if the properties are valid 91*7fb33566SCarson Labrado static void addSatelliteConfig( 92*7fb33566SCarson Labrado const dbus::utility::DBusPropertiesMap& properties, 93*7fb33566SCarson Labrado std::unordered_map<std::string, boost::urls::url>& satelliteInfo) 94*7fb33566SCarson Labrado { 95*7fb33566SCarson Labrado boost::urls::url url; 96*7fb33566SCarson Labrado std::string name; 97*7fb33566SCarson Labrado 98*7fb33566SCarson Labrado for (const auto& prop : properties) 99*7fb33566SCarson Labrado { 100*7fb33566SCarson Labrado if (prop.first == "Name") 101*7fb33566SCarson Labrado { 102*7fb33566SCarson Labrado const std::string* propVal = 103*7fb33566SCarson Labrado std::get_if<std::string>(&prop.second); 104*7fb33566SCarson Labrado if (propVal == nullptr) 105*7fb33566SCarson Labrado { 106*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid Name value"; 107*7fb33566SCarson Labrado return; 108*7fb33566SCarson Labrado } 109*7fb33566SCarson Labrado 110*7fb33566SCarson Labrado // The IDs will become <Name>_<ID> so the name should not 111*7fb33566SCarson Labrado // contain a '_' 112*7fb33566SCarson Labrado if (propVal->find('_') != std::string::npos) 113*7fb33566SCarson Labrado { 114*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Name cannot contain a \"_\""; 115*7fb33566SCarson Labrado return; 116*7fb33566SCarson Labrado } 117*7fb33566SCarson Labrado name = *propVal; 118*7fb33566SCarson Labrado } 119*7fb33566SCarson Labrado 120*7fb33566SCarson Labrado else if (prop.first == "Hostname") 121*7fb33566SCarson Labrado { 122*7fb33566SCarson Labrado const std::string* propVal = 123*7fb33566SCarson Labrado std::get_if<std::string>(&prop.second); 124*7fb33566SCarson Labrado if (propVal == nullptr) 125*7fb33566SCarson Labrado { 126*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid Hostname value"; 127*7fb33566SCarson Labrado return; 128*7fb33566SCarson Labrado } 129*7fb33566SCarson Labrado url.set_host(*propVal); 130*7fb33566SCarson Labrado } 131*7fb33566SCarson Labrado 132*7fb33566SCarson Labrado else if (prop.first == "Port") 133*7fb33566SCarson Labrado { 134*7fb33566SCarson Labrado const uint64_t* propVal = std::get_if<uint64_t>(&prop.second); 135*7fb33566SCarson Labrado if (propVal == nullptr) 136*7fb33566SCarson Labrado { 137*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid Port value"; 138*7fb33566SCarson Labrado return; 139*7fb33566SCarson Labrado } 140*7fb33566SCarson Labrado 141*7fb33566SCarson Labrado if (*propVal > std::numeric_limits<uint16_t>::max()) 142*7fb33566SCarson Labrado { 143*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Port value out of range"; 144*7fb33566SCarson Labrado return; 145*7fb33566SCarson Labrado } 146*7fb33566SCarson Labrado url.set_port(static_cast<uint16_t>(*propVal)); 147*7fb33566SCarson Labrado } 148*7fb33566SCarson Labrado 149*7fb33566SCarson Labrado else if (prop.first == "AuthType") 150*7fb33566SCarson Labrado { 151*7fb33566SCarson Labrado const std::string* propVal = 152*7fb33566SCarson Labrado std::get_if<std::string>(&prop.second); 153*7fb33566SCarson Labrado if (propVal == nullptr) 154*7fb33566SCarson Labrado { 155*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Invalid AuthType value"; 156*7fb33566SCarson Labrado return; 157*7fb33566SCarson Labrado } 158*7fb33566SCarson Labrado 159*7fb33566SCarson Labrado // For now assume authentication not required to communicate 160*7fb33566SCarson Labrado // with the satellite BMC 161*7fb33566SCarson Labrado if (*propVal != "None") 162*7fb33566SCarson Labrado { 163*7fb33566SCarson Labrado BMCWEB_LOG_ERROR 164*7fb33566SCarson Labrado << "Unsupported AuthType value: " << *propVal 165*7fb33566SCarson Labrado << ", only \"none\" is supported"; 166*7fb33566SCarson Labrado return; 167*7fb33566SCarson Labrado } 168*7fb33566SCarson Labrado url.set_scheme("http"); 169*7fb33566SCarson Labrado } 170*7fb33566SCarson Labrado } // Finished reading properties 171*7fb33566SCarson Labrado 172*7fb33566SCarson Labrado // Make sure all required config information was made available 173*7fb33566SCarson Labrado if (name.empty()) 174*7fb33566SCarson Labrado { 175*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config missing Name"; 176*7fb33566SCarson Labrado return; 177*7fb33566SCarson Labrado } 178*7fb33566SCarson Labrado 179*7fb33566SCarson Labrado if (url.host().empty()) 180*7fb33566SCarson Labrado { 181*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config " << name << " missing Host"; 182*7fb33566SCarson Labrado return; 183*7fb33566SCarson Labrado } 184*7fb33566SCarson Labrado 185*7fb33566SCarson Labrado if (!url.has_port()) 186*7fb33566SCarson Labrado { 187*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config " << name << " missing Port"; 188*7fb33566SCarson Labrado return; 189*7fb33566SCarson Labrado } 190*7fb33566SCarson Labrado 191*7fb33566SCarson Labrado if (!url.has_scheme()) 192*7fb33566SCarson Labrado { 193*7fb33566SCarson Labrado BMCWEB_LOG_ERROR << "Satellite config " << name 194*7fb33566SCarson Labrado << " missing AuthType"; 195*7fb33566SCarson Labrado return; 196*7fb33566SCarson Labrado } 197*7fb33566SCarson Labrado 198*7fb33566SCarson Labrado std::string resultString; 199*7fb33566SCarson Labrado auto result = satelliteInfo.insert_or_assign(name, std::move(url)); 200*7fb33566SCarson Labrado if (result.second) 201*7fb33566SCarson Labrado { 202*7fb33566SCarson Labrado resultString = "Added new satellite config "; 203*7fb33566SCarson Labrado } 204*7fb33566SCarson Labrado else 205*7fb33566SCarson Labrado { 206*7fb33566SCarson Labrado resultString = "Updated existing satellite config "; 207*7fb33566SCarson Labrado } 208*7fb33566SCarson Labrado 209*7fb33566SCarson Labrado BMCWEB_LOG_DEBUG << resultString << name << " at " 210*7fb33566SCarson Labrado << result.first->second.scheme() << "://" 211*7fb33566SCarson Labrado << result.first->second.encoded_host_and_port(); 212*7fb33566SCarson Labrado } 213*7fb33566SCarson Labrado 214*7fb33566SCarson Labrado public: 215*7fb33566SCarson Labrado RedfishAggregator(const RedfishAggregator&) = delete; 216*7fb33566SCarson Labrado RedfishAggregator& operator=(const RedfishAggregator&) = delete; 217*7fb33566SCarson Labrado RedfishAggregator(RedfishAggregator&&) = delete; 218*7fb33566SCarson Labrado RedfishAggregator& operator=(RedfishAggregator&&) = delete; 219*7fb33566SCarson Labrado ~RedfishAggregator() = default; 220*7fb33566SCarson Labrado 221*7fb33566SCarson Labrado static RedfishAggregator& getInstance() 222*7fb33566SCarson Labrado { 223*7fb33566SCarson Labrado static RedfishAggregator handler; 224*7fb33566SCarson Labrado return handler; 225*7fb33566SCarson Labrado } 226*7fb33566SCarson Labrado }; 227*7fb33566SCarson Labrado 228*7fb33566SCarson Labrado } // namespace redfish 229