Implement AggregationSource
Adds an AggregationSource resource for each satellite config present on
dbus.
Adds the AggregationSource schema which we had previously ignored.
Tested:
Querying an AggregationSource returned the expected information.
curl localhost/redfish/v1/AggregationService/AggregationSources/5B247A
{
"@odata.id": "/redfish/v1/AggregationService/AggregationSources/5B247A",
"@odata.type": "#AggregationSource.v1_3_1.AggregationSource",
"HostName": "http://122.111.11.1:80",
"Id": "5B247A",
"Name": "Aggregation source",
"Password": null,
}
Service Validator passed. The Service Validator also passed after
removing the satellite config from the system such that
/redfish/v1/AggregationService/AggregationSources returns an empty
Members array.
Signed-off-by: Carson Labrado <clabrado@google.com>
Change-Id: I88b5fbc15f27cddd330ec22a25427fd8b18cf766
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 954dfc7..cf41824 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -73,8 +73,9 @@
{
requestAccountServiceRoutes(app);
#ifdef BMCWEB_ENABLE_REDFISH_AGGREGATION
- requestAggregationServiceRoutes(app);
- requestAggregationSourcesRoutes(app);
+ requestRoutesAggregationService(app);
+ requestRoutesAggregationSourceCollection(app);
+ requestRoutesAggregationSource(app);
#endif
requestRoutesRoles(app);
requestRoutesRoleCollection(app);
diff --git a/redfish-core/include/redfish_aggregator.hpp b/redfish-core/include/redfish_aggregator.hpp
index de51ca6..85c1c15 100644
--- a/redfish-core/include/redfish_aggregator.hpp
+++ b/redfish-core/include/redfish_aggregator.hpp
@@ -239,55 +239,20 @@
// Dummy callback used by the Constructor so that it can report the number
// of satellite configs when the class is first created
static void constructorCallback(
+ const boost::system::error_code& ec,
const std::unordered_map<std::string, boost::urls::url>& satelliteInfo)
{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Something went wrong while querying dbus!";
+ return;
+ }
+
BMCWEB_LOG_DEBUG << "There were "
<< std::to_string(satelliteInfo.size())
<< " satellite configs found at startup";
}
- // Polls D-Bus to get all available satellite config information
- // Expects a handler which interacts with the returned configs
- static void getSatelliteConfigs(
- const std::function<void(
- const std::unordered_map<std::string, boost::urls::url>&)>& handler)
- {
- BMCWEB_LOG_DEBUG << "Gathering satellite configs";
- crow::connections::systemBus->async_method_call(
- [handler](const boost::system::error_code& ec,
- const dbus::utility::ManagedObjectType& objects) {
- if (ec)
- {
- BMCWEB_LOG_ERROR << "DBUS response error " << ec.value() << ", "
- << ec.message();
- return;
- }
-
- // Maps a chosen alias representing a satellite BMC to a url
- // containing the information required to create a http
- // connection to the satellite
- std::unordered_map<std::string, boost::urls::url> satelliteInfo;
-
- findSatelliteConfigs(objects, satelliteInfo);
-
- if (!satelliteInfo.empty())
- {
- BMCWEB_LOG_DEBUG << "Redfish Aggregation enabled with "
- << std::to_string(satelliteInfo.size())
- << " satellite BMCs";
- }
- else
- {
- BMCWEB_LOG_DEBUG
- << "No satellite BMCs detected. Redfish Aggregation not enabled";
- }
- handler(satelliteInfo);
- },
- "xyz.openbmc_project.EntityManager",
- "/xyz/openbmc_project/inventory",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- }
-
// Search D-Bus objects for satellite config objects and add their
// information if valid
static void findSatelliteConfigs(
@@ -492,12 +457,19 @@
AggregationType isCollection,
const std::shared_ptr<crow::Request>& sharedReq,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code& ec,
const std::unordered_map<std::string, boost::urls::url>& satelliteInfo)
{
if (sharedReq == nullptr)
{
return;
}
+ // Something went wrong while querying dbus
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
// No satellite configs means we don't need to keep attempting to
// aggregate
@@ -631,6 +603,51 @@
return handler;
}
+ // Polls D-Bus to get all available satellite config information
+ // Expects a handler which interacts with the returned configs
+ static void getSatelliteConfigs(
+ std::function<
+ void(const boost::system::error_code&,
+ const std::unordered_map<std::string, boost::urls::url>&)>
+ handler)
+ {
+ BMCWEB_LOG_DEBUG << "Gathering satellite configs";
+ crow::connections::systemBus->async_method_call(
+ [handler{std::move(handler)}](
+ const boost::system::error_code& ec,
+ const dbus::utility::ManagedObjectType& objects) {
+ std::unordered_map<std::string, boost::urls::url> satelliteInfo;
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error " << ec.value() << ", "
+ << ec.message();
+ handler(ec, satelliteInfo);
+ return;
+ }
+
+ // Maps a chosen alias representing a satellite BMC to a url
+ // containing the information required to create a http
+ // connection to the satellite
+ findSatelliteConfigs(objects, satelliteInfo);
+
+ if (!satelliteInfo.empty())
+ {
+ BMCWEB_LOG_DEBUG << "Redfish Aggregation enabled with "
+ << std::to_string(satelliteInfo.size())
+ << " satellite BMCs";
+ }
+ else
+ {
+ BMCWEB_LOG_DEBUG
+ << "No satellite BMCs detected. Redfish Aggregation not enabled";
+ }
+ handler(ec, satelliteInfo);
+ },
+ "xyz.openbmc_project.EntityManager",
+ "/xyz/openbmc_project/inventory",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ }
+
// Processes the response returned by a satellite BMC and loads its
// contents into asyncResp
static void
@@ -863,7 +880,11 @@
{
// We've matched a resource collection so this current segment
// might contain an aggregation prefix
- if (collectionItem.starts_with("5B247A"))
+ // TODO: This needs to be rethought when we can support multiple
+ // satellites due to
+ // /redfish/v1/AggregationService/AggregationSources/5B247A
+ // being a local resource describing the satellite
+ if (collectionItem.starts_with("5B247A_"))
{
BMCWEB_LOG_DEBUG << "Need to forward a request";
diff --git a/redfish-core/include/schemas.hpp b/redfish-core/include/schemas.hpp
index c2cbb8b..8dd2d7b 100644
--- a/redfish-core/include/schemas.hpp
+++ b/redfish-core/include/schemas.hpp
@@ -18,6 +18,7 @@
"AccountService",
"ActionInfo",
"AggregationService",
+ "AggregationSource",
"AggregationSourceCollection",
"Assembly",
"AttributeRegistry",
diff --git a/redfish-core/lib/aggregation_service.hpp b/redfish-core/lib/aggregation_service.hpp
index f0eb651..1cd2e68 100644
--- a/redfish-core/lib/aggregation_service.hpp
+++ b/redfish-core/lib/aggregation_service.hpp
@@ -5,6 +5,7 @@
#include "http_request.hpp"
#include "http_response.hpp"
#include "query.hpp"
+#include "redfish_aggregator.hpp"
#include "registries/privilege_registry.hpp"
#include <nlohmann/json.hpp>
@@ -50,7 +51,7 @@
"/redfish/v1/AggregationService/AggregationSources";
}
-inline void requestAggregationServiceRoutes(App& app)
+inline void requestRoutesAggregationService(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/")
.privileges(redfish::privileges::headAggregationService)
@@ -62,7 +63,31 @@
std::bind_front(handleAggregationServiceGet, std::ref(app)));
}
-inline void handleAggregationSourcesGet(
+inline void populateAggregationSourceCollection(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code ec,
+ const std::unordered_map<std::string, boost::urls::url>& satelliteInfo)
+{
+ // Something went wrong while querying dbus
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ nlohmann::json::array_t members = nlohmann::json::array();
+ for (const auto& sat : satelliteInfo)
+ {
+ nlohmann::json::object_t member;
+ member["@odata.id"] =
+ crow::utility::urlFromPieces("redfish", "v1", "AggregationService",
+ "AggregationSources", sat.first);
+ members.push_back(std::move(member));
+ }
+ asyncResp->res.jsonValue["Members@odata.count"] = members.size();
+ asyncResp->res.jsonValue["Members"] = std::move(members);
+}
+
+inline void handleAggregationSourceCollectionGet(
App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
{
@@ -78,18 +103,124 @@
json["@odata.type"] =
"#AggregationSourceCollection.AggregationSourceCollection";
json["Name"] = "Aggregation Source Collection";
- json["Members"] = nlohmann::json::array();
- json["Members@odata.count"] = 0;
- // TODO: Query D-Bus for satellite configs and add them to the Members array
+ // Query D-Bus for satellite configs and add them to the Members array
+ RedfishAggregator::getSatelliteConfigs(
+ std::bind_front(populateAggregationSourceCollection, asyncResp));
}
-inline void requestAggregationSourcesRoutes(App& app)
+inline void handleAggregationSourceCollectionHead(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ asyncResp->res.addHeader(
+ boost::beast::http::field::link,
+ "</redfish/v1/JsonSchemas/AggregationService/AggregationSourceCollection.json>; rel=describedby");
+}
+
+inline void requestRoutesAggregationSourceCollection(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/AggregationSources/")
- .privileges(redfish::privileges::getAggregationService)
+ .privileges(redfish::privileges::getAggregationSourceCollection)
+ .methods(boost::beast::http::verb::get)(std::bind_front(
+ handleAggregationSourceCollectionGet, std::ref(app)));
+
+ BMCWEB_ROUTE(app, "/redfish/v1/AggregationService/AggregationSources/")
+ .privileges(redfish::privileges::getAggregationSourceCollection)
+ .methods(boost::beast::http::verb::head)(std::bind_front(
+ handleAggregationSourceCollectionHead, std::ref(app)));
+}
+
+inline void populateAggregationSource(
+ const std::string& aggregationSourceId,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code ec,
+ const std::unordered_map<std::string, boost::urls::url>& satelliteInfo)
+{
+ asyncResp->res.addHeader(
+ boost::beast::http::field::link,
+ "</redfish/v1/JsonSchemas/AggregationSource/AggregationSource.json>; rel=describedby");
+
+ // Something went wrong while querying dbus
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ const auto& sat = satelliteInfo.find(aggregationSourceId);
+ if (sat == satelliteInfo.end())
+ {
+ messages::resourceNotFound(asyncResp->res, "AggregationSource",
+ aggregationSourceId);
+ return;
+ }
+
+ asyncResp->res.jsonValue["@odata.id"] =
+ crow::utility::urlFromPieces("redfish", "v1", "AggregationService",
+ "AggregationSources", aggregationSourceId);
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#AggregationSource.v1_3_1.AggregationSource";
+ asyncResp->res.jsonValue["Id"] = aggregationSourceId;
+
+ // TODO: We may want to change this whenever we support aggregating multiple
+ // satellite BMCs. Otherwise all AggregationSource resources will have the
+ // same "Name".
+ // TODO: We should use the "Name" from the satellite config whenever we add
+ // support for including it in the data returned in satelliteInfo.
+ asyncResp->res.jsonValue["Name"] = "Aggregation source";
+ std::string hostName(sat->second.encoded_origin());
+ asyncResp->res.jsonValue["HostName"] = std::move(hostName);
+
+ // The Redfish spec requires Password to be null in responses
+ asyncResp->res.jsonValue["Password"] = nullptr;
+}
+
+inline void handleAggregationSourceGet(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& aggregationSourceId)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+
+ // Query D-Bus for satellite config corresponding to the specified
+ // AggregationSource
+ RedfishAggregator::getSatelliteConfigs(std::bind_front(
+ populateAggregationSource, aggregationSourceId, asyncResp));
+}
+
+inline void handleAggregationSourceHead(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& aggregationSourceId)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ asyncResp->res.addHeader(
+ boost::beast::http::field::link,
+ "</redfish/v1/JsonSchemas/AggregationService/AggregationSource.json>; rel=describedby");
+
+ // Needed to prevent unused variable error
+ BMCWEB_LOG_DEBUG << "Added link header to response from "
+ << aggregationSourceId;
+}
+
+inline void requestRoutesAggregationSource(App& app)
+{
+ BMCWEB_ROUTE(app,
+ "/redfish/v1/AggregationService/AggregationSources/<str>/")
+ .privileges(redfish::privileges::getAggregationSource)
.methods(boost::beast::http::verb::get)(
- std::bind_front(handleAggregationSourcesGet, std::ref(app)));
+ std::bind_front(handleAggregationSourceGet, std::ref(app)));
}
} // namespace redfish