Restrict Redfish expand query features when RDE devices are present Google-Bug-Id:553082322 PiperOrigin-RevId: 971521741 Change-Id: I29b1e0862015974c705223035a585e1d4bf54a6c
diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp index 25dcef9..412334c 100644 --- a/redfish-core/lib/service_root.hpp +++ b/redfish-core/lib/service_root.hpp
@@ -25,10 +25,13 @@ #include "app.hpp" #include "http_request.hpp" #include "async_resp.hpp" +#include "dbus_utility.hpp" #include "persistent_data.hpp" #include "query.hpp" #include "registries/privilege_registry.hpp" #include <nlohmann/json.hpp> +#include "managed_store.hpp" +#include "managed_store_types.hpp" namespace redfish { @@ -84,22 +87,43 @@ nlohmann::json& protocolFeatures = asyncResp->res.jsonValue["ProtocolFeaturesSupported"]; protocolFeatures["ExcerptQuery"] = false; - - protocolFeatures["ExpandQuery"]["ExpandAll"] = - bmcwebInsecureEnableQueryParams; - // This is the maximum level defined in ServiceRoot.v1_13_0.json - if (bmcwebInsecureEnableQueryParams) { - protocolFeatures["ExpandQuery"]["MaxLevels"] = 6; - } - protocolFeatures["ExpandQuery"]["Levels"] = bmcwebInsecureEnableQueryParams; - protocolFeatures["ExpandQuery"]["Links"] = bmcwebInsecureEnableQueryParams; - protocolFeatures["ExpandQuery"]["NoLinks"] = bmcwebInsecureEnableQueryParams; protocolFeatures["FilterQuery"] = true; protocolFeatures["TopSkipQuery"] = true; protocolFeatures["OnlyMemberQuery"] = true; protocolFeatures["SelectQuery"] = true; protocolFeatures["DeepOperations"]["DeepPOST"] = false; protocolFeatures["DeepOperations"]["DeepPATCH"] = false; + + managedStore::ManagedObjectStoreContext requestContext(asyncResp); + managedStore::GetManagedObjectStore()->getSubTreePaths( + "/xyz/openbmc_project/rde_devices", 0, {}, requestContext, + [asyncResp](const boost::system::error_code& ec, + const dbus::utility::MapperGetSubTreePathsResponse& objects) { + nlohmann::json& protocolFeatures = + asyncResp->res.jsonValue["ProtocolFeaturesSupported"]; + // If we detect rde devices, then we cannot support expand queries. + if (!ec && !objects.empty()) { + protocolFeatures["ExpandQuery"]["ExpandAll"] = false; + protocolFeatures["ExpandQuery"]["Levels"] = false; + protocolFeatures["ExpandQuery"]["Links"] = false; + protocolFeatures["ExpandQuery"]["MaxLevels"] = 1; + protocolFeatures["ExpandQuery"]["NoLinks"] = false; + return; + } + + protocolFeatures["ExpandQuery"]["ExpandAll"] = + bmcwebInsecureEnableQueryParams; + // This is the maximum level defined in ServiceRoot.v1_13_0.json + if (bmcwebInsecureEnableQueryParams) { + protocolFeatures["ExpandQuery"]["MaxLevels"] = 6; + } + protocolFeatures["ExpandQuery"]["Levels"] = + bmcwebInsecureEnableQueryParams; + protocolFeatures["ExpandQuery"]["Links"] = + bmcwebInsecureEnableQueryParams; + protocolFeatures["ExpandQuery"]["NoLinks"] = + bmcwebInsecureEnableQueryParams; + }); } inline void handleServiceRootGet( App& app, const crow::Request& req,
diff --git a/test/redfish-core/lib/service_root_test.cpp b/test/redfish-core/lib/service_root_test.cpp index 6d27991..4485371 100644 --- a/test/redfish-core/lib/service_root_test.cpp +++ b/test/redfish-core/lib/service_root_test.cpp
@@ -1,75 +1,198 @@ #include "service_root.hpp" +#include <filesystem> #include <memory> +#include <string> +#include <system_error> +#include <vector> #include <gtest/gtest.h> -#include "bmcweb_config.h" #include "http_response.hpp" -#include "async_resp.hpp" +#include "test/redfish-core/lib/snapshot_fixture.hpp" #include <nlohmann/json.hpp> +#include "managed_store.hpp" +#include "managed_store_types.hpp" +#include "test/g3/mock_managed_store.hpp" +#include "test/g3/mock_managed_store_test.hpp" namespace redfish { namespace { +using ::managedStore::KeyType; +using ::managedStore::ManagedType; + void assertServiceRootGet(crow::Response& res) { - nlohmann::json& json = res.jsonValue; - EXPECT_EQ(json["@odata.id"], "/redfish/v1"); - EXPECT_EQ(json["@odata.type"], "#ServiceRoot.v1_15_0.ServiceRoot"); - EXPECT_EQ(json["CertificateService"]["@odata.id"], - "/redfish/v1/CertificateService"); - EXPECT_EQ(json["CertificateService"].size(), 1); - EXPECT_EQ(json["Chassis"]["@odata.id"], "/redfish/v1/Chassis"); - EXPECT_EQ(json["Chassis"].size(), 1); - EXPECT_EQ(json["Id"], "RootService"); - EXPECT_EQ(json["Links"].size(), 1); - EXPECT_EQ(json["Links"]["ManagerProvidingService"].size(), 1); - EXPECT_EQ(json["Links"]["ManagerProvidingService"]["@odata.id"], - "/redfish/v1/Managers/bmc"); - EXPECT_EQ(json["Managers"]["@odata.id"], "/redfish/v1/Managers"); - EXPECT_EQ(json["Managers"].size(), 1); - EXPECT_EQ(json["Name"], "Root Service"); - EXPECT_EQ(json["RedfishVersion"], "1.9.0"); - EXPECT_EQ(json["Storage"]["@odata.id"], "/redfish/v1/Storage"); - EXPECT_EQ(json["Storage"].size(), 1); - EXPECT_EQ(json["Systems"]["@odata.id"], "/redfish/v1/Systems"); - EXPECT_EQ(json["Systems"].size(), 1); - EXPECT_EQ(json["Tasks"]["@odata.id"], "/redfish/v1/TaskService"); - EXPECT_EQ(json["Tasks"].size(), 1); - EXPECT_EQ(json["TelemetryService"]["@odata.id"], - "/redfish/v1/TelemetryService"); - EXPECT_EQ(json["TelemetryService"].size(), 1); - EXPECT_EQ(json["UpdateService"]["@odata.id"], "/redfish/v1/UpdateService"); - EXPECT_EQ(json["ProtocolFeaturesSupported"].size(), 7); - EXPECT_FALSE(json["ProtocolFeaturesSupported"]["ExcerptQuery"]); - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"]["ExpandAll"], - bmcwebInsecureEnableQueryParams); - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"]["Levels"], - bmcwebInsecureEnableQueryParams); - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"]["Links"], - bmcwebInsecureEnableQueryParams); - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"]["NoLinks"], - bmcwebInsecureEnableQueryParams); - if (bmcwebInsecureEnableQueryParams) { - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"].size(), 5); - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"]["MaxLevels"], 6); - } else { - EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"].size(), 4); - } - EXPECT_TRUE(json["ProtocolFeaturesSupported"]["FilterQuery"]); - EXPECT_TRUE(json["ProtocolFeaturesSupported"]["OnlyMemberQuery"]); - EXPECT_TRUE(json["ProtocolFeaturesSupported"]["SelectQuery"]); - EXPECT_TRUE(json["ProtocolFeaturesSupported"]["TopSkipQuery"]); - EXPECT_FALSE(json["ProtocolFeaturesSupported"]["DeepOperations"]["DeepPOST"]); - EXPECT_FALSE( - json["ProtocolFeaturesSupported"]["DeepOperations"]["DeepPATCH"]); - EXPECT_EQ(json["ProtocolFeaturesSupported"]["DeepOperations"].size(), 2); - EXPECT_EQ(json.size(), 18); + nlohmann::json json = res.jsonValue; + EXPECT_FALSE(json["UUID"].empty()); + json.erase("UUID"); + + EXPECT_EQ(json, nlohmann::json::parse(R"({ + "@odata.id": "/redfish/v1", + "@odata.type": "#ServiceRoot.v1_15_0.ServiceRoot", + "Cables": { + "@odata.id": "/redfish/v1/Cables" + }, + "CertificateService": { + "@odata.id": "/redfish/v1/CertificateService" + }, + "Chassis": { + "@odata.id": "/redfish/v1/Chassis" + }, + "ComponentIntegrity": { + "@odata.id": "/redfish/v1/ComponentIntegrity" + }, + "Id": "RootService", + "JsonSchemas": { + "@odata.id": "/redfish/v1/JsonSchemas" + }, + "Links": { + "ManagerProvidingService": { + "@odata.id": "/redfish/v1/Managers/bmc" + } + }, + "Managers": { + "@odata.id": "/redfish/v1/Managers" + }, + "Name": "Root Service", + "ProtocolFeaturesSupported": { + "DeepOperations": { + "DeepPATCH": false, + "DeepPOST": false + }, + "ExcerptQuery": false, + "ExpandQuery": { + "ExpandAll": true, + "Levels": true, + "Links": true, + "MaxLevels": 6, + "NoLinks": true + }, + "FilterQuery": true, + "OnlyMemberQuery": true, + "SelectQuery": true, + "TopSkipQuery": true + }, + "RedfishVersion": "1.9.0", + "Storage": { + "@odata.id": "/redfish/v1/Storage" + }, + "Systems": { + "@odata.id": "/redfish/v1/Systems" + }, + "Tasks": { + "@odata.id": "/redfish/v1/TaskService" + }, + "TelemetryService": { + "@odata.id": "/redfish/v1/TelemetryService" + }, + "UpdateService": { + "@odata.id": "/redfish/v1/UpdateService" + } + })")); } -TEST(HandleServiceRootGet, ServiceRootStaticAttributesAreExpected) { - auto shareAsyncResp = std::make_shared<bmcweb::AsyncResp>(); - shareAsyncResp->res.setCompleteRequestHandler(assertServiceRootGet); - redfish::handleServiceRootGetImpl(shareAsyncResp); +class ServiceRootTest : public SnapshotFixture { + protected: + void SetUp() override { + SnapshotFixture::SetUp(); + std::error_code ec; + orig_path_ = std::filesystem::current_path(ec); + std::filesystem::current_path(std::filesystem::temp_directory_path(ec), ec); + } + + void TearDown() override { + std::error_code ec; + std::filesystem::current_path(orig_path_, ec); + SnapshotFixture::TearDown(); + } + + std::filesystem::path orig_path_; +}; + +TEST_F(ServiceRootTest, HandleServiceRootHeadSetsLinkHeader) { + handleServiceRootHead(app_, CreateRequest(), share_async_resp_); + EXPECT_FALSE( + share_async_resp_->res.getHeaderValue("Link").empty()); +} + +TEST_F(ServiceRootTest, HandleServiceRootUuidPopulatesUuid) { + handleServiceRootUuid(share_async_resp_); + EXPECT_FALSE(share_async_resp_->res.jsonValue["UUID"].empty()); +} + +TEST_F(ServiceRootTest, HandleServiceRootGetImplMiniBmcDetected) { + KeyType key(ManagedType::kManagedSubtreePaths, + "/xyz/openbmc_project/rde_devices", 0, {}); + std::vector<std::string> paths = { + "/xyz/openbmc_project/rde_devices/1_1_5_3_1", + }; + ASSERT_TRUE( + dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( + managedStore::GetManagedObjectStore()) + ->upsertMockObjectIntoManagedStore( + key, managedStore::MockManagedStoreTest::CreateValueType(paths)) + .ok()); + + handleServiceRootGetImpl(share_async_resp_); + RunIoUntilDone(); + + nlohmann::json& json = share_async_resp_->res.jsonValue; + EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"], + nlohmann::json::parse(R"({ + "ExpandAll": false, + "Levels": false, + "Links": false, + "MaxLevels": 1, + "NoLinks": false + })")); +} + +TEST_F(ServiceRootTest, HandleServiceRootGetImplEmptyRdeDevices) { + KeyType key(ManagedType::kManagedSubtreePaths, + "/xyz/openbmc_project/rde_devices", 0, {}); + std::vector<std::string> emptyPaths; + ASSERT_TRUE( + dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( + managedStore::GetManagedObjectStore()) + ->upsertMockObjectIntoManagedStore( + key, + managedStore::MockManagedStoreTest::CreateValueType(emptyPaths)) + .ok()); + + handleServiceRootGetImpl(share_async_resp_); + RunIoUntilDone(); + + nlohmann::json& json = share_async_resp_->res.jsonValue; + EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"], + nlohmann::json::parse(R"({ + "ExpandAll": true, + "Levels": true, + "Links": true, + "MaxLevels": 6, + "NoLinks": true + })")); +} + +TEST_F(ServiceRootTest, HandleServiceRootGetImplDbusErrorFallsBackToDefault) { + // Key not in cache simulates D-Bus / mapper error in snapshot mode + handleServiceRootGetImpl(share_async_resp_); + RunIoUntilDone(); + + nlohmann::json& json = share_async_resp_->res.jsonValue; + EXPECT_EQ(json["ProtocolFeaturesSupported"]["ExpandQuery"], + nlohmann::json::parse(R"({ + "ExpandAll": true, + "Levels": true, + "Links": true, + "MaxLevels": 6, + "NoLinks": true + })")); +} + +TEST_F(ServiceRootTest, ServiceRootStaticAttributesAreExpected) { + handleServiceRootGet(app_, CreateRequest(), share_async_resp_); + RunIoUntilDone(); + assertServiceRootGet(share_async_resp_->res); } } // namespace