summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Labrado <clabrado@google.com>2022-08-01 22:38:18 +0300
committerEd Tanous <edtanous@google.com>2022-08-24 00:47:32 +0300
commit05916cef0fce4dd2532e1e7e33f6abc4dcf339be (patch)
treea4cad67bda45206f9b0e95c70b5811ec142da53f
parent7f8d8fa938f521d18278e9cb5673bacd83217d09 (diff)
downloadbmcweb-05916cef0fce4dd2532e1e7e33f6abc4dcf339be.tar.xz
Aggregation: Prepare for routing requests
We do not want to allow a HW config to set its own prefix since that results in HW choosing and hardcoding resource URIs. Removes using "Name" from the satellite config as the config's prefix. For now assume there will be no more than one satellite bmc. We will always assign that config to be "aggregated0". If more than one config is present then we will not attempt to forward any requests. In a future patch we will add support for aggregating multiple satellite BMCs. The aggregator will be responsible for assigning the prefixes to each satellite. When we receive a request we parse the resource ID to see if it begins with "aggregated" and thus should be forwarded to a satellite BMC. In those cases we should not locally handle the request. We return a 500 error, but in a future patch that will be replaced by the actual code to forward the request to the appropriate satellite. Requests for resource collections need to be both handled locally and forwarded. Place holders are added for where the forwarding will occur. A future patch will add that functionality. Tested: Exposed two configs in an entity-manager json: "Exposes": [ { "Hostname": "127.0.0.1", "Port": "443", "Name": "Sat1", "Type": "SatelliteController", "AuthType": "None" }, { "Hostname": "127.0.0.1", "Port": "444", "Name": "Sat2", "Type": "SatelliteController", "AuthType": "None" }, It produced an error that only one satellite is supported and as a result both configs were ignored. I removed the second config and that resulted in the first (and only) config being added as "aggregated0". Requests for local resources were ignored by the aggregation code. Requests for collections hit the forward collection endpoints and return local results. 500 returned for satellite resources such as: /redfish/v1/Chassis/aggregated0_Fake /redfish/v1/UpdateService/FirmwareInventory/aggregated0_Fake /redfish/v1/UpdateService/SoftwareInventory/aggregated0_Fake Change-Id: I5c860c01534e7d5b1a37c95f75be5b3c1f695816 Signed-off-by: Carson Labrado <clabrado@google.com> Signed-off-by: Ed Tanous <edtanous@google.com>
-rw-r--r--redfish-core/include/query.hpp16
-rw-r--r--redfish-core/include/redfish_aggregator.hpp124
2 files changed, 109 insertions, 31 deletions
diff --git a/redfish-core/include/query.hpp b/redfish-core/include/query.hpp
index fd5d189193..007b262244 100644
--- a/redfish-core/include/query.hpp
+++ b/redfish-core/include/query.hpp
@@ -27,6 +27,8 @@
// IWYU pragma: no_include <boost/url/impl/params_view.hpp>
// IWYU pragma: no_include <boost/url/impl/url_view.hpp>
+#include <redfish_aggregator.hpp>
+
namespace redfish
{
@@ -62,10 +64,20 @@ namespace redfish
return false;
}
+ bool needToCallHandlers = true;
+
+#ifdef BMCWEB_ENABLE_REDFISH_AGGREGATION
+ needToCallHandlers = RedfishAggregator::getInstance().beginAggregation(
+ req, asyncResp) == Result::LocalHandle;
+
+ // If the request should be forwarded to a satellite BMC then we don't want
+ // to write anything to the asyncResp since it will get overwritten later.
+#endif
+
// If this isn't a get, no need to do anything with parameters
if (req.method() != boost::beast::http::verb::get)
{
- return true;
+ return needToCallHandlers;
}
delegated = query_param::delegate(queryCapabilities, *queryOpt);
@@ -78,7 +90,7 @@ namespace redfish
processAllParams(app, query, handler, resIn);
});
- return true;
+ return needToCallHandlers;
}
// Sets up the Redfish Route. All parameters are handled by the default handler.
diff --git a/redfish-core/include/redfish_aggregator.hpp b/redfish-core/include/redfish_aggregator.hpp
index 33f6fb4b53..0a5ff57d90 100644
--- a/redfish-core/include/redfish_aggregator.hpp
+++ b/redfish-core/include/redfish_aggregator.hpp
@@ -5,6 +5,27 @@
namespace redfish
{
+enum class Result
+{
+ LocalHandle,
+ NoLocalHandle
+};
+
+// Checks if the provided path is related to one of the resource collections
+// under UpdateService
+static inline bool
+ isUpdateServiceCollection(const std::vector<std::string>& segments)
+{
+ if (segments.size() < 4)
+ {
+ return false;
+ }
+
+ return (segments[2] == "UpdateService") &&
+ ((segments[3] == "FirmwareInventory") ||
+ (segments[3] == "SoftwareInventory"));
+}
+
class RedfishAggregator
{
private:
@@ -105,7 +126,19 @@ class RedfishAggregator
BMCWEB_LOG_DEBUG << "Found Satellite Controller at "
<< objectPath.first.str;
- addSatelliteConfig(interface.second, satelliteInfo);
+ if (!satelliteInfo.empty())
+ {
+ BMCWEB_LOG_ERROR
+ << "Redfish Aggregation only supports one satellite!";
+ BMCWEB_LOG_DEBUG << "Clearing all satellite data";
+ satelliteInfo.clear();
+ return;
+ }
+
+ // For now assume there will only be one satellite config.
+ // Assign it the name/prefix "5B247A"
+ addSatelliteConfig("5B247A", interface.second,
+ satelliteInfo);
}
}
}
@@ -114,35 +147,15 @@ class RedfishAggregator
// Parse the properties of a satellite config object and add the
// configuration if the properties are valid
static void addSatelliteConfig(
+ const std::string& name,
const dbus::utility::DBusPropertiesMap& properties,
std::unordered_map<std::string, boost::urls::url>& satelliteInfo)
{
boost::urls::url url;
- std::string name;
for (const auto& prop : properties)
{
- if (prop.first == "Name")
- {
- const std::string* propVal =
- std::get_if<std::string>(&prop.second);
- if (propVal == nullptr)
- {
- BMCWEB_LOG_ERROR << "Invalid Name value";
- return;
- }
-
- // The IDs will become <Name>_<ID> so the name should not
- // contain a '_'
- if (propVal->find('_') != std::string::npos)
- {
- BMCWEB_LOG_ERROR << "Name cannot contain a \"_\"";
- return;
- }
- name = *propVal;
- }
-
- else if (prop.first == "Hostname")
+ if (prop.first == "Hostname")
{
const std::string* propVal =
std::get_if<std::string>(&prop.second);
@@ -195,12 +208,6 @@ class RedfishAggregator
} // Finished reading properties
// Make sure all required config information was made available
- if (name.empty())
- {
- BMCWEB_LOG_ERROR << "Satellite config missing Name";
- return;
- }
-
if (url.host().empty())
{
BMCWEB_LOG_ERROR << "Satellite config " << name << " missing Host";
@@ -248,6 +255,65 @@ class RedfishAggregator
static RedfishAggregator handler;
return handler;
}
+
+ // Entry point to Redfish Aggregation
+ // Returns Result stating whether or not we still need to locally handle the
+ // request
+ static Result
+ beginAggregation(const crow::Request& thisReq,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+ {
+ using crow::utility::OrMorePaths;
+ using crow::utility::readUrlSegments;
+ const boost::urls::url_view& url = thisReq.urlView;
+ // UpdateService is the only top level resource that is not a Collection
+ if (readUrlSegments(url, "redfish", "v1", "UpdateService"))
+ {
+ return Result::LocalHandle;
+ }
+
+ // Is the request for a resource collection?:
+ // /redfish/v1/<resource>
+ // e.g. /redfish/v1/Chassis
+ std::string collectionName;
+ if (readUrlSegments(url, "redfish", "v1", std::ref(collectionName)))
+ {
+ return Result::LocalHandle;
+ }
+
+ // We know that the ID of an aggregated resource will begin with
+ // "5B247A". For the most part the URI will begin like this:
+ // /redfish/v1/<resource>/<resource ID>
+ // Note, FirmwareInventory and SoftwareInventory are "special" because
+ // they are two levels deep, but still need aggregated
+ // /redfish/v1/UpdateService/FirmwareInventory/<FirmwareInventory ID>
+ // /redfish/v1/UpdateService/SoftwareInventory/<SoftwareInventory ID>
+ std::string memberName;
+ if (readUrlSegments(url, "redfish", "v1", "UpdateService",
+ "SoftwareInventory", std::ref(memberName),
+ OrMorePaths()) ||
+ readUrlSegments(url, "redfish", "v1", "UpdateService",
+ "FirmwareInventory", std::ref(memberName),
+ OrMorePaths()) ||
+ readUrlSegments(url, "redfish", "v1", std::ref(collectionName),
+ std::ref(memberName), OrMorePaths()))
+ {
+ if (memberName.starts_with("5B247A"))
+ {
+ BMCWEB_LOG_DEBUG << "Need to forward a request";
+
+ // TODO: Extract the prefix from the request's URI, retrieve
+ // the associated satellite config information, and then
+ // forward the request to that satellite.
+ redfish::messages::internalError(asyncResp->res);
+ return Result::NoLocalHandle;
+ }
+ return Result::LocalHandle;
+ }
+
+ BMCWEB_LOG_DEBUG << "Aggregation not required";
+ return Result::LocalHandle;
+ }
};
} // namespace redfish