summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Labrado <clabrado@google.com>2023-01-03 20:30:47 +0300
committerEd Tanous <ed@tanous.net>2023-04-07 01:16:56 +0300
commit8fd333d664f87c73757e0c5e58c611dc0c3e76d7 (patch)
tree0babf511e86ce1980f42a8dab157f92ad5939a17
parente628df8658c57f6943b6d3612e1077618e5a168a (diff)
downloadbmcweb-8fd333d664f87c73757e0c5e58c611dc0c3e76d7.tar.xz
Aggregation: Check for subordinate collection
Adds a search function which is able to determine if a passed URI is a top level collection, is uptree from a top level collection, or both. The type being searched for depends on a second argument passed to the function. Each of these searches are used to add links to top level collections which are only supported by a satellite BMC. They all use similar steps so rolling them into a single function cuts down on redundant code. Adds test cases to verify the implementation is correct. Tested: New test cases pass Signed-off-by: Carson Labrado <clabrado@google.com> Change-Id: I72ae7442d5f314656b57a73aee544bca516fa7c2
-rw-r--r--redfish-core/include/redfish_aggregator.hpp105
-rw-r--r--test/redfish-core/include/redfish_aggregator_test.cpp129
2 files changed, 234 insertions, 0 deletions
diff --git a/redfish-core/include/redfish_aggregator.hpp b/redfish-core/include/redfish_aggregator.hpp
index c640586c10..245c698233 100644
--- a/redfish-core/include/redfish_aggregator.hpp
+++ b/redfish-core/include/redfish_aggregator.hpp
@@ -21,6 +21,14 @@ enum class Result
NoLocalHandle
};
+enum class SearchType
+{
+ Collection,
+ CollOrCon,
+ ContainsSubordinate,
+ Resource
+};
+
// clang-format off
// These are all of the properties as of version 2022.2 of the Redfish Resource
// and Schema Guide whose Type is "string (URI)" and the name does not end in a
@@ -43,6 +51,103 @@ constexpr std::array nonUriProperties{
};
// clang-format on
+// Search the top collection array to determine if the passed URI is of a
+// desired type
+inline bool searchCollectionsArray(std::string_view uri,
+ const SearchType searchType)
+{
+ constexpr std::string_view serviceRootUri = "/redfish/v1";
+
+ // The passed URI must begin with "/redfish/v1", but we have to strip it
+ // from the URI since topCollections does not include it in its URIs
+ if (!uri.starts_with(serviceRootUri))
+ {
+ return false;
+ }
+
+ // Catch empty final segments such as "/redfish/v1/Chassis//"
+ if (uri.ends_with("//"))
+ {
+ return false;
+ }
+
+ std::size_t parseCount = uri.size() - serviceRootUri.size();
+ // Don't include the trailing "/" if it exists such as in "/redfish/v1/"
+ if (uri.ends_with("/"))
+ {
+ parseCount--;
+ }
+
+ boost::urls::result<boost::urls::url_view> parsedUrl =
+ boost::urls::parse_relative_ref(
+ uri.substr(serviceRootUri.size(), parseCount));
+ if (!parsedUrl)
+ {
+ BMCWEB_LOG_ERROR << "Failed to get target URI from "
+ << uri.substr(serviceRootUri.size());
+ return false;
+ }
+
+ if (!parsedUrl->segments().is_absolute() && !parsedUrl->segments().empty())
+ {
+ return false;
+ }
+
+ // If no segments() then the passed URI was either "/redfish/v1" or
+ // "/redfish/v1/".
+ if (parsedUrl->segments().empty())
+ {
+ return (searchType == SearchType::ContainsSubordinate) ||
+ (searchType == SearchType::CollOrCon);
+ }
+
+ const auto* it = std::lower_bound(
+ topCollections.begin(), topCollections.end(), parsedUrl->buffer());
+ if (it == topCollections.end())
+ {
+ // parsedUrl is alphabetically after the last entry in the array so it
+ // can't be a top collection or up tree from a top collection
+ return false;
+ }
+
+ boost::urls::url collectionUrl(*it);
+ boost::urls::segments_view collectionSegments = collectionUrl.segments();
+ boost::urls::segments_view::iterator itCollection =
+ collectionSegments.begin();
+ const boost::urls::segments_view::const_iterator endCollection =
+ collectionSegments.end();
+
+ // Each segment in the passed URI should match the found collection
+ for (const auto& segment : parsedUrl->segments())
+ {
+ if (itCollection == endCollection)
+ {
+ // Leftover segments means the target is for an aggregation
+ // supported resource
+ return searchType == SearchType::Resource;
+ }
+
+ if (segment != (*itCollection))
+ {
+ return false;
+ }
+ itCollection++;
+ }
+
+ // No remaining segments means the passed URI was a top level collection
+ if (searchType == SearchType::Collection)
+ {
+ return itCollection == endCollection;
+ }
+ if (searchType == SearchType::ContainsSubordinate)
+ {
+ return itCollection != endCollection;
+ }
+
+ // Return this check instead of "true" in case other SearchTypes get added
+ return searchType == SearchType::CollOrCon;
+}
+
// Determines if the passed property contains a URI. Those property names
// either end with a case-insensitive version of "uri" or are specifically
// defined in the above array.
diff --git a/test/redfish-core/include/redfish_aggregator_test.cpp b/test/redfish-core/include/redfish_aggregator_test.cpp
index 2fdd784d3b..da3209ab9b 100644
--- a/test/redfish-core/include/redfish_aggregator_test.cpp
+++ b/test/redfish-core/include/redfish_aggregator_test.cpp
@@ -518,5 +518,134 @@ TEST(processResponse, DifferentContentType)
assertProcessResponseContentType(";charset=utf-8");
}
+bool containsSubordinateCollection(const std::string_view uri)
+{
+ return searchCollectionsArray(uri, SearchType::ContainsSubordinate);
+}
+
+bool containsCollection(const std::string_view uri)
+{
+ return searchCollectionsArray(uri, SearchType::Collection);
+}
+
+bool isCollOrCon(const std::string_view uri)
+{
+ return searchCollectionsArray(uri, SearchType::CollOrCon);
+}
+
+TEST(searchCollectionsArray, containsSubordinateValidURIs)
+{
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/"));
+ EXPECT_TRUE(
+ containsSubordinateCollection("/redfish/v1/AggregationService"));
+ EXPECT_TRUE(
+ containsSubordinateCollection("/redfish/v1/CompositionService/"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/JobService"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/JobService/Log"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/KeyService"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/LicenseService/"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/PowerEquipment"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/TaskService"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/TelemetryService"));
+ EXPECT_TRUE(containsSubordinateCollection(
+ "/redfish/v1/TelemetryService/LogService/"));
+ EXPECT_TRUE(containsSubordinateCollection("/redfish/v1/UpdateService"));
+}
+
+TEST(searchCollectionsArray, containsSubordinateInvalidURIs)
+{
+ EXPECT_FALSE(containsSubordinateCollection(""));
+ EXPECT_FALSE(containsSubordinateCollection("http://"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish/"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish//"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish/v1//"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish/v11"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish/v11/"));
+ EXPECT_FALSE(containsSubordinateCollection("www.test.com/redfish/v1"));
+ EXPECT_FALSE(containsSubordinateCollection("/fail"));
+ EXPECT_FALSE(containsSubordinateCollection(
+ "/redfish/v1/AggregationService/Aggregates"));
+ EXPECT_FALSE(containsSubordinateCollection(
+ "/redfish/v1/AggregationService/AggregationSources/"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish/v1/Cables/"));
+ EXPECT_FALSE(
+ containsSubordinateCollection("/redfish/v1/Chassis/chassisId"));
+ EXPECT_FALSE(containsSubordinateCollection("/redfish/v1/Fake"));
+ EXPECT_FALSE(
+ containsSubordinateCollection("/redfish/v1/TelemetryService//"));
+ EXPECT_FALSE(containsSubordinateCollection(
+ "/redfish/v1/TelemetryService/LogService/Entries"));
+ EXPECT_FALSE(containsSubordinateCollection(
+ "/redfish/v1/UpdateService/SoftwareInventory/"));
+ EXPECT_FALSE(containsSubordinateCollection(
+ "/redfish/v1/UpdateService/SoftwareInventory/Te"));
+ EXPECT_FALSE(containsSubordinateCollection(
+ "/redfish/v1/UpdateService/SoftwareInventory2"));
+}
+
+TEST(searchCollectionsArray, collectionURIs)
+{
+ EXPECT_TRUE(containsCollection("/redfish/v1/Chassis"));
+ EXPECT_TRUE(containsCollection("/redfish/v1/Chassis/"));
+ EXPECT_TRUE(containsCollection("/redfish/v1/Managers"));
+ EXPECT_TRUE(containsCollection("/redfish/v1/Systems"));
+ EXPECT_TRUE(
+ containsCollection("/redfish/v1/TelemetryService/LogService/Entries"));
+ EXPECT_TRUE(
+ containsCollection("/redfish/v1/TelemetryService/LogService/Entries/"));
+ EXPECT_TRUE(
+ containsCollection("/redfish/v1/UpdateService/FirmwareInventory"));
+ EXPECT_TRUE(
+ containsCollection("/redfish/v1/UpdateService/FirmwareInventory/"));
+
+ EXPECT_FALSE(containsCollection("http://"));
+ EXPECT_FALSE(containsCollection("/redfish/v11/Chassis"));
+ EXPECT_FALSE(containsCollection("/redfish/v11/Chassis/"));
+ EXPECT_FALSE(containsCollection("/redfish/v1"));
+ EXPECT_FALSE(containsCollection("/redfish/v1/"));
+ EXPECT_FALSE(containsCollection("/redfish/v1//"));
+ EXPECT_FALSE(containsCollection("/redfish/v1/Chassis//"));
+ EXPECT_FALSE(containsCollection("/redfish/v1/Chassis/Test"));
+ EXPECT_FALSE(containsCollection("/redfish/v1/TelemetryService"));
+ EXPECT_FALSE(containsCollection("/redfish/v1/TelemetryService/"));
+ EXPECT_FALSE(containsCollection("/redfish/v1/UpdateService"));
+ EXPECT_FALSE(
+ containsCollection("/redfish/v1/UpdateService/FirmwareInventory/Test"));
+ EXPECT_FALSE(
+ containsCollection("/redfish/v1/UpdateService/FirmwareInventory/Tes/"));
+ EXPECT_FALSE(
+ containsCollection("/redfish/v1/UpdateService/SoftwareInventory/Te"));
+ EXPECT_FALSE(
+ containsCollection("/redfish/v1/UpdateService/SoftwareInventory2"));
+ EXPECT_FALSE(containsCollection("/redfish/v11"));
+ EXPECT_FALSE(containsCollection("/redfish/v11/"));
+}
+
+TEST(searchCollectionsArray, collectionOrContainsURIs)
+{
+ // Resources that are a top level collection or are uptree of one
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/AggregationService"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/CompositionService/"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/Chassis"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/Cables/"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/Fabrics"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/Managers"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/UpdateService/FirmwareInventory"));
+ EXPECT_TRUE(isCollOrCon("/redfish/v1/UpdateService/FirmwareInventory/"));
+
+ EXPECT_FALSE(isCollOrCon("http://"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v11"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v11/"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v1/Chassis/Test"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v1/Managers/Test/"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v1/TaskService/Tasks/0"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v1/UpdateService/FirmwareInventory/Te"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v1/UpdateService/SoftwareInventory/Te"));
+ EXPECT_FALSE(isCollOrCon("/redfish/v1/UpdateService/SoftwareInventory2"));
+}
+
} // namespace
} // namespace redfish