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