summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Labrado <clabrado@google.com>2022-05-18 03:12:52 +0300
committerEd Tanous <edtanous@google.com>2022-08-24 00:47:32 +0300
commit1c0bb5c6f90b772150accb1f590227589e2179ff (patch)
tree8c3a66c0ea158098f5a2dcd178e1bf297977e429
parent46a81465f991637341b0a877b3a027db58a3d330 (diff)
downloadbmcweb-1c0bb5c6f90b772150accb1f590227589e2179ff.tar.xz
Redfish Aggregation: Fixup aggregated URIs
URIs in the responses returned with Redfish Aggregation enabled will potentially be incorrect since ones from satellite BMCs will not include the associated prefix such as "5B247A_" in the resource ID portion of the URIs. This patch fixes those links so that they include their BMC's associated prefix. Note that a future patch will be needed to add prefixes to aggregated resources that would appear under collection URIs such as "/redfish/v1/Chassis". Tested: Requests were sent to URIs associated with the aggregating BMC and a satellite BMC denoted as "5B247A". The URIs in the responses were successfully updated such that "5B247A_" was added for satellite resources. Signed-off-by: Carson Labrado <clabrado@google.com> Signed-off-by: Ed Tanous <edtanous@google.com> Change-Id: Ib4f976fab1ca1e8603f7cf55292732ffb71cd03e
-rw-r--r--http/utility.hpp30
-rw-r--r--redfish-core/include/redfish_aggregator.hpp127
2 files changed, 153 insertions, 4 deletions
diff --git a/http/utility.hpp b/http/utility.hpp
index 2ba9b0ea08..d4b9b67421 100644
--- a/http/utility.hpp
+++ b/http/utility.hpp
@@ -672,6 +672,36 @@ inline bool readUrlSegments(const boost::urls::url_view& urlView,
return details::readUrlSegments(urlView, {std::forward<Args>(args)...});
}
+inline boost::urls::url replaceUrlSegment(const boost::urls::url_view& urlView,
+ const uint replaceLoc,
+ const std::string_view newSegment)
+{
+ const boost::urls::segments_view& urlSegments = urlView.segments();
+ boost::urls::url url("/");
+
+ if (!urlSegments.is_absolute())
+ {
+ return url;
+ }
+
+ boost::urls::segments_view::iterator it = urlSegments.begin();
+ boost::urls::segments_view::iterator end = urlSegments.end();
+
+ for (uint idx = 0; it != end; it++, idx++)
+ {
+ if (idx == replaceLoc)
+ {
+ url.segments().push_back(newSegment);
+ }
+ else
+ {
+ url.segments().push_back(*it);
+ }
+ }
+
+ return url;
+}
+
inline std::string setProtocolDefaults(const boost::urls::url_view& url)
{
if (url.scheme() == "https")
diff --git a/redfish-core/include/redfish_aggregator.hpp b/redfish-core/include/redfish_aggregator.hpp
index e0e35219a3..6e2671c45f 100644
--- a/redfish-core/include/redfish_aggregator.hpp
+++ b/redfish-core/include/redfish_aggregator.hpp
@@ -14,6 +14,122 @@ enum class Result
NoLocalHandle
};
+static void addPrefixToItem(nlohmann::json& item, std::string_view prefix)
+{
+ std::string* strValue = item.get_ptr<std::string*>();
+ if (strValue == nullptr)
+ {
+ BMCWEB_LOG_CRITICAL << "Field wasn't a string????";
+ return;
+ }
+ // Make sure the value is a properly formatted URI
+ auto parsed = boost::urls::parse_relative_ref(*strValue);
+ if (!parsed)
+ {
+ BMCWEB_LOG_CRITICAL << "Couldn't parse URI from resource " << *strValue;
+ return;
+ }
+
+ boost::urls::url_view thisUrl = *parsed;
+
+ // We don't need to add prefixes to these URIs since
+ // /redfish/v1/UpdateService/ itself is not a collection
+ // /redfish/v1/UpdateService/FirmwareInventory
+ // /redfish/v1/UpdateService/SoftwareInventory
+ if (crow::utility::readUrlSegments(thisUrl, "redfish", "v1",
+ "UpdateService", "FirmwareInventory") ||
+ crow::utility::readUrlSegments(thisUrl, "redfish", "v1",
+ "UpdateService", "SoftwareInventory"))
+ {
+ BMCWEB_LOG_DEBUG << "Skipping UpdateService URI prefix fixing";
+ return;
+ }
+
+ // We also need to aggregate FirmwareInventory and
+ // SoftwareInventory so add an extra offset
+ // /redfish/v1/UpdateService/FirmwareInventory/<id>
+ // /redfish/v1/UpdateService/SoftwareInventory/<id>
+ std::string collectionName;
+ std::string softwareItem;
+ if (crow::utility::readUrlSegments(
+ thisUrl, "redfish", "v1", "UpdateService", std::ref(collectionName),
+ std::ref(softwareItem), crow::utility::OrMorePaths()))
+ {
+ softwareItem.insert(0, "_");
+ softwareItem.insert(0, prefix);
+ item = crow::utility::replaceUrlSegment(thisUrl, 4, softwareItem);
+ }
+
+ // A collection URI that ends with "/" such as
+ // "/redfish/v1/Chassis/" will have 4 segments so we need to
+ // make sure we don't try to add a prefix to an empty segment
+ if (crow::utility::readUrlSegments(
+ thisUrl, "redfish", "v1", std::ref(collectionName),
+ std::ref(softwareItem), crow::utility::OrMorePaths()))
+ {
+ softwareItem.insert(0, "_");
+ softwareItem.insert(0, prefix);
+ item = crow::utility::replaceUrlSegment(thisUrl, 3, softwareItem);
+ }
+}
+
+// We need to attempt to update all URIs under Actions
+static void addPrefixesToActions(nlohmann::json& json, std::string_view prefix)
+{
+ nlohmann::json::object_t* object =
+ json.get_ptr<nlohmann::json::object_t*>();
+ if (object != nullptr)
+ {
+ for (std::pair<const std::string, nlohmann::json>& item : *object)
+ {
+ std::string* strValue = item.second.get_ptr<std::string*>();
+ if (strValue != nullptr)
+ {
+ addPrefixToItem(item.second, prefix);
+ }
+ else
+ {
+ addPrefixesToActions(item.second, prefix);
+ }
+ }
+ }
+}
+
+// Search the json for all URIs and add the supplied prefix if the URI is for
+// and aggregated resource.
+static void addPrefixes(nlohmann::json& json, std::string_view prefix)
+{
+ nlohmann::json::object_t* object =
+ json.get_ptr<nlohmann::json::object_t*>();
+ if (object != nullptr)
+ {
+ for (std::pair<const std::string, nlohmann::json>& item : *object)
+ {
+ if (item.first == "Actions")
+ {
+ addPrefixesToActions(item.second, prefix);
+ continue;
+ }
+
+ if ((item.first == "@odata.id") || (item.first.ends_with("URI")))
+ {
+ addPrefixToItem(item.second, prefix);
+ }
+ // Recusively parse the rest of the json
+ addPrefixes(item.second, prefix);
+ }
+ return;
+ }
+ nlohmann::json::array_t* array = json.get_ptr<nlohmann::json::array_t*>();
+ if (array != nullptr)
+ {
+ for (nlohmann::json& item : *array)
+ {
+ addPrefixes(item, prefix);
+ }
+ }
+}
+
class RedfishAggregator
{
private:
@@ -364,7 +480,7 @@ class RedfishAggregator
targetURI.erase(pos, prefix.size() + 1);
std::function<void(crow::Response&)> cb =
- std::bind_front(processResponse, asyncResp);
+ std::bind_front(processResponse, prefix, asyncResp);
std::string data = thisReq.req.body();
crow::HttpClient::getInstance().sendDataWithCallback(
@@ -376,7 +492,8 @@ class RedfishAggregator
// Processes the response returned by a satellite BMC and loads its
// contents into asyncResp
static void
- processResponse(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ processResponse(std::string_view prefix,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
crow::Response& resp)
{
// No processing needed if the request wasn't successful
@@ -406,6 +523,10 @@ class RedfishAggregator
// our response rather than just straight overwriting them if our
// local handling was successful (i.e. would return a 200).
+ addPrefixes(jsonVal, prefix);
+
+ BMCWEB_LOG_DEBUG << "Added prefix to parsed satellite response";
+
asyncResp->res.stringResponse.emplace(
boost::beast::http::response<
boost::beast::http::string_body>{});
@@ -413,8 +534,6 @@ class RedfishAggregator
asyncResp->res.jsonValue = std::move(jsonVal);
BMCWEB_LOG_DEBUG << "Finished writing asyncResp";
- // TODO: Need to fix the URIs in the response so that they include
- // the prefix
}
else
{