diff options
-rw-r--r-- | include/webserver_common.hpp | 24 | ||||
-rw-r--r-- | redfish-core/include/node.hpp | 69 | ||||
-rw-r--r-- | redfish-core/include/redfish.hpp | 6 | ||||
-rw-r--r-- | redfish-core/lib/account_service.hpp | 32 | ||||
-rw-r--r-- | redfish-core/lib/redfish_sessions.hpp | 43 | ||||
-rw-r--r-- | redfish-core/lib/roles.hpp | 48 | ||||
-rw-r--r-- | redfish-core/lib/service_root.hpp | 24 | ||||
-rw-r--r-- | src/webserver_main.cpp | 6 |
8 files changed, 143 insertions, 109 deletions
diff --git a/include/webserver_common.hpp b/include/webserver_common.hpp new file mode 100644 index 0000000000..fcfd3218d8 --- /dev/null +++ b/include/webserver_common.hpp @@ -0,0 +1,24 @@ +/* +// Copyright (c) 2018 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ +#pragma once + +#include "token_authorization_middleware.hpp" +#include "webserver_common.hpp" + +using CrowApp = crow::App<crow::PersistentData::Middleware, + crow::TokenAuthorization::Middleware, + crow::SecurityHeadersMiddleware>; + diff --git a/redfish-core/include/node.hpp b/redfish-core/include/node.hpp index a76e5b370e..908d1a6a64 100644 --- a/redfish-core/include/node.hpp +++ b/redfish-core/include/node.hpp @@ -17,6 +17,7 @@ #include "privileges.hpp" #include "token_authorization_middleware.hpp" +#include "webserver_common.hpp" #include "crow.h" namespace redfish { @@ -27,7 +28,7 @@ namespace redfish { */ class Node { public: - template <typename CrowApp, typename... Params> + template <typename... Params> Node(CrowApp& app, EntityPrivileges&& entityPrivileges, std::string&& entityUrl, Params... params) : entityPrivileges(std::move(entityPrivileges)) { @@ -42,6 +43,49 @@ class Node { virtual ~Node() = default; + std::string getUrl() const { + auto odataId = json.find("@odata.id"); + if (odataId != json.end() && odataId->is_string()) { + return odataId->get<std::string>(); + } + return std::string(); + } + + /** + * @brief Inserts subroute fields into for the node's json in the form: + * "subroute_name" : { "odata.id": "node_url/subroute_name/" } + * Excludes metadata urls starting with "$" and child urls having + * more than one level. + * + * @return None + */ + void getSubRoutes(const std::vector<std::unique_ptr<Node>>& allNodes) { + std::string url = getUrl(); + + for (const auto& node : allNodes) { + auto route = node->getUrl(); + + if (boost::starts_with(route, url)) { + auto subRoute = route.substr(url.size()); + if (subRoute.empty()) { + continue; + } + + if (subRoute.at(0) == '/') { + subRoute = subRoute.substr(1); + } + + if (subRoute.at(subRoute.size() - 1) == '/') { + subRoute = subRoute.substr(0, subRoute.size() - 1); + } + + if (subRoute[0] != '$' && subRoute.find('/') == std::string::npos) { + json[subRoute] = nlohmann::json{{"@odata.id", route}}; + } + } + } + } + protected: // Node is designed to be an abstract class, so doGet is pure virtual virtual void doGet(crow::response& res, const crow::request& req, @@ -65,8 +109,9 @@ class Node { res.end(); } + nlohmann::json json; + private: - template <typename CrowApp> void dispatchRequest(CrowApp& app, const crow::request& req, crow::response& res, const std::vector<std::string>& params) { @@ -107,24 +152,4 @@ class Node { EntityPrivileges entityPrivileges; }; -template <typename CrowApp> -void getRedfishSubRoutes(CrowApp& app, const std::string& url, - nlohmann::json& j) { - std::vector<const std::string*> routes = app.get_routes(url); - - for (auto route : routes) { - auto redfishSubRoute = - route->substr(url.size(), route->size() - url.size() - 1); - - // Exclude: - exact matches, - // - metadata urls starting with "$", - // - urls at the same level - if (!redfishSubRoute.empty() && redfishSubRoute[0] != '$' && - redfishSubRoute.find('/') == std::string::npos) { - j[redfishSubRoute] = nlohmann::json{{"@odata.id", *route}}; - } - } -} - } // namespace redfish - diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index 0e059b8678..fc8c0800a6 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -19,6 +19,7 @@ #include "../lib/redfish_sessions.hpp" #include "../lib/roles.hpp" #include "../lib/service_root.hpp" +#include "webserver_common.hpp" namespace redfish { /* @@ -33,13 +34,16 @@ class RedfishService { * * @param[in] app Crow app on which Redfish will initialize */ - template <typename CrowApp> RedfishService(CrowApp& app) { nodes.emplace_back(std::make_unique<AccountService>(app)); nodes.emplace_back(std::make_unique<SessionCollection>(app)); nodes.emplace_back(std::make_unique<Roles>(app)); nodes.emplace_back(std::make_unique<RoleCollection>(app)); nodes.emplace_back(std::make_unique<ServiceRoot>(app)); + + for (auto& node : nodes) { + node->getSubRoutes(nodes); + } } private: diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp index 5cbc034f11..dafa6055a3 100644 --- a/redfish-core/lib/account_service.hpp +++ b/redfish-core/lib/account_service.hpp @@ -33,31 +33,29 @@ class AccountService : public Node { AccountService(CrowApp& app) : Node(app, EntityPrivileges(std::move(accountServiceOpMap)), "/redfish/v1/AccountService/") { - nodeJson["@odata.id"] = "/redfish/v1/AccountService"; - nodeJson["@odata.type"] = "#AccountService.v1_1_0.AccountService"; - nodeJson["@odata.context"] = + Node::json["@odata.id"] = "/redfish/v1/AccountService"; + Node::json["@odata.type"] = "#AccountService.v1_1_0.AccountService"; + Node::json["@odata.context"] = "/redfish/v1/$metadata#AccountService.AccountService"; - nodeJson["Id"] = "AccountService"; - nodeJson["Description"] = "BMC User Accounts"; - nodeJson["Name"] = "Account Service"; - nodeJson["Status"]["State"] = "Enabled"; - nodeJson["Status"]["Health"] = "OK"; - nodeJson["Status"]["HealthRollup"] = "OK"; - nodeJson["ServiceEnabled"] = true; - nodeJson["MinPasswordLength"] = 1; - nodeJson["MaxPasswordLength"] = 20; - nodeJson["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts"; - nodeJson["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles"; + Node::json["Id"] = "AccountService"; + Node::json["Description"] = "BMC User Accounts"; + Node::json["Name"] = "Account Service"; + Node::json["Status"]["State"] = "Enabled"; + Node::json["Status"]["Health"] = "OK"; + Node::json["Status"]["HealthRollup"] = "OK"; + Node::json["ServiceEnabled"] = true; + Node::json["MinPasswordLength"] = 1; + Node::json["MaxPasswordLength"] = 20; + Node::json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts"; + Node::json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles"; } private: void doGet(crow::response& res, const crow::request& req, const std::vector<std::string>& params) override { - res.json_value = nodeJson; + res.json_value = Node::json; res.end(); } - - nlohmann::json nodeJson; }; } // namespace redfish diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp index 58d5b94912..75857a1528 100644 --- a/redfish-core/lib/redfish_sessions.hpp +++ b/redfish-core/lib/redfish_sessions.hpp @@ -40,14 +40,13 @@ class SessionCollection; class Sessions : public Node { public: - template <typename CrowApp> Sessions(CrowApp& app) : Node(app, EntityPrivileges(std::move(sessionOpMap)), "/redfish/v1/SessionService/Sessions/<str>", std::string()) { - nodeJson["@odata.type"] = "#Session.v1_0_2.Session"; - nodeJson["@odata.context"] = "/redfish/v1/$metadata#Session.Session"; - nodeJson["Name"] = "User Session"; - nodeJson["Description"] = "Manager User Session"; + Node::json["@odata.type"] = "#Session.v1_0_2.Session"; + Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session"; + Node::json["Name"] = "User Session"; + Node::json["Description"] = "Manager User Session"; } private: @@ -62,12 +61,12 @@ class Sessions : public Node { return; } - nodeJson["Id"] = session->unique_id; - nodeJson["UserName"] = session->username; - nodeJson["@odata.id"] = + Node::json["Id"] = session->unique_id; + Node::json["UserName"] = session->username; + Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/" + session->unique_id; - res.json_value = nodeJson; + res.json_value = Node::json; res.end(); } @@ -100,25 +99,22 @@ class Sessions : public Node { * data for created member which should match member's doGet result in 100% */ friend SessionCollection; - - nlohmann::json nodeJson; }; class SessionCollection : public Node { public: - template <typename CrowApp> SessionCollection(CrowApp& app) : Node(app, EntityPrivileges(std::move(sessionCollectionOpMap)), "/redfish/v1/SessionService/Sessions/"), memberSession(app) { - nodeJson["@odata.type"] = "#SessionCollection.SessionCollection"; - nodeJson["@odata.id"] = "/redfish/v1/SessionService/Sessions/"; - nodeJson["@odata.context"] = + Node::json["@odata.type"] = "#SessionCollection.SessionCollection"; + Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/"; + Node::json["@odata.context"] = "/redfish/v1/$metadata#SessionCollection.SessionCollection"; - nodeJson["Name"] = "Session Collection"; - nodeJson["Description"] = "Session Collection"; - nodeJson["Members@odata.count"] = 0; - nodeJson["Members"] = nlohmann::json::array(); + Node::json["Name"] = "Session Collection"; + Node::json["Description"] = "Session Collection"; + Node::json["Members@odata.count"] = 0; + Node::json["Members"] = nlohmann::json::array(); } private: @@ -128,14 +124,14 @@ class SessionCollection : public Node { crow::PersistentData::session_store->get_unique_ids( false, crow::PersistentData::PersistenceType::TIMEOUT); - nodeJson["Members@odata.count"] = session_ids.size(); - nodeJson["Members"] = nlohmann::json::array(); + Node::json["Members@odata.count"] = session_ids.size(); + Node::json["Members"] = nlohmann::json::array(); for (const auto& uid : session_ids) { - nodeJson["Members"].push_back( + Node::json["Members"].push_back( {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}}); } - res.json_value = nodeJson; + res.json_value = Node::json; res.end(); } @@ -235,7 +231,6 @@ class SessionCollection : public Node { * member's doGet, as they should return 100% matching data */ Sessions memberSession; - nlohmann::json nodeJson; }; } // namespace redfish diff --git a/redfish-core/lib/roles.hpp b/redfish-core/lib/roles.hpp index 6a3c0d704e..f1a1c61b84 100644 --- a/redfish-core/lib/roles.hpp +++ b/redfish-core/lib/roles.hpp @@ -37,58 +37,52 @@ static OperationMap roleCollectionOpMap = { class Roles : public Node { public: - template <typename CrowApp> Roles(CrowApp& app) : Node(app, EntityPrivileges(std::move(roleOpMap)), "/redfish/v1/AccountService/Roles/Administrator/") { - nodeJson["@odata.id"] = "/redfish/v1/AccountService/Roles/Administrator"; - nodeJson["@odata.type"] = "#Role.v1_0_2.Role"; - nodeJson["@odata.context"] = "/redfish/v1/$metadata#Role.Role"; - nodeJson["Id"] = "Administrator"; - nodeJson["Name"] = "User Role"; - nodeJson["Description"] = "Administrator User Role"; - nodeJson["IsPredefined"] = true; - nodeJson["AssignedPrivileges"] = {"Login", "ConfigureManager", - "ConfigureUsers", "ConfigureSelf", - "ConfigureComponents"}; - nodeJson["OemPrivileges"] = nlohmann::json::array(); + Node::json["@odata.id"] = "/redfish/v1/AccountService/Roles/Administrator"; + Node::json["@odata.type"] = "#Role.v1_0_2.Role"; + Node::json["@odata.context"] = "/redfish/v1/$metadata#Role.Role"; + Node::json["Id"] = "Administrator"; + Node::json["Name"] = "User Role"; + Node::json["Description"] = "Administrator User Role"; + Node::json["IsPredefined"] = true; + Node::json["AssignedPrivileges"] = {"Login", "ConfigureManager", + "ConfigureUsers", "ConfigureSelf", + "ConfigureComponents"}; + Node::json["OemPrivileges"] = nlohmann::json::array(); } private: void doGet(crow::response& res, const crow::request& req, const std::vector<std::string>& params) override { - res.json_value = nodeJson; + res.json_value = Node::json; res.end(); } - - nlohmann::json nodeJson; }; class RoleCollection : public Node { public: - template <typename CrowApp> RoleCollection(CrowApp& app) : Node(app, EntityPrivileges(std::move(roleCollectionOpMap)), "/redfish/v1/AccountService/Roles/") { - nodeJson["@odata.id"] = "/redfish/v1/AccountService/Roles"; - nodeJson["@odata.type"] = "#RoleCollection.RoleCollection"; - nodeJson["@odata.context"] = + Node::json["@odata.id"] = "/redfish/v1/AccountService/Roles"; + Node::json["@odata.type"] = "#RoleCollection.RoleCollection"; + Node::json["@odata.context"] = "/redfish/v1/$metadata#RoleCollection.RoleCollection"; - nodeJson["Name"] = "Roles Collection"; - nodeJson["Description"] = "BMC User Roles"; - nodeJson["Members@odata.count"] = 1; - nodeJson["Members"] = { - {{"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}}; + Node::json["Name"] = "Roles Collection"; + Node::json["Description"] = "BMC User Roles"; + Node::json["Members@odata.count"] = 1; + Node::json["Members"] = { + {"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}; } private: void doGet(crow::response& res, const crow::request& req, const std::vector<std::string>& params) override { - res.json_value = nodeJson; + res.json_value = Node::json; res.end(); } - - nlohmann::json nodeJson; }; } // namespace redfish diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp index 24ad79d308..129d58d85d 100644 --- a/redfish-core/lib/service_root.hpp +++ b/redfish-core/lib/service_root.hpp @@ -29,34 +29,30 @@ static OperationMap serviceRootOpMap = { class ServiceRoot : public Node { public: - template <typename CrowApp> ServiceRoot(CrowApp& app) : Node(app, EntityPrivileges(std::move(serviceRootOpMap)), "/redfish/v1/") { - nodeJson["@odata.type"] = "#ServiceRoot.v1_1_1.ServiceRoot"; - nodeJson["@odata.id"] = "/redfish/v1"; - nodeJson["@odata.context"] = + Node::json["@odata.type"] = "#ServiceRoot.v1_1_1.ServiceRoot"; + Node::json["@odata.id"] = "/redfish/v1/"; + Node::json["@odata.context"] = "/redfish/v1/$metadata#ServiceRoot.ServiceRoot"; - nodeJson["Id"] = "RootService"; - nodeJson["Name"] = "Root Service"; - nodeJson["RedfishVersion"] = "1.1.0"; - nodeJson["Links"]["Sessions"] = { - {"@odata.id", "/redfish/v1/SessionService/Sessions/"}}; - nodeJson["UUID"] = + Node::json["Id"] = "RootService"; + Node::json["Name"] = "Root Service"; + Node::json["RedfishVersion"] = "1.1.0"; + Node::json["Links"]["Sessions"] = { + {"@odata.id", "/redfish/v1/SessionService/Sessions"}}; + Node::json["UUID"] = app.template get_middleware<crow::PersistentData::Middleware>() .system_uuid; - getRedfishSubRoutes(app, "/redfish/v1/", nodeJson); } private: void doGet(crow::response& res, const crow::request& req, const std::vector<std::string>& params) override { res.add_header("Content-Type", "application/json"); - res.body = nodeJson.dump(); + res.json_value = Node::json; res.end(); } - - nlohmann::json nodeJson; }; } // namespace redfish diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp index f504cc7ed8..53dd12742b 100644 --- a/src/webserver_main.cpp +++ b/src/webserver_main.cpp @@ -13,6 +13,7 @@ #include <memory> #include <string> #include "redfish.hpp" +#include "webserver_common.hpp" #include <crow/app.h> #include <boost/asio.hpp> #include <systemd/sd-daemon.h> @@ -43,10 +44,7 @@ int main(int argc, char** argv) { auto io = std::make_shared<boost::asio::io_service>(); crow::PersistentData::session_store = std::make_shared<crow::PersistentData::SessionStore>(); - crow::App<crow::PersistentData::Middleware, - crow::TokenAuthorization::Middleware, - crow::SecurityHeadersMiddleware> - app(io); + CrowApp app(io); #ifdef CROW_ENABLE_SSL std::string ssl_pem_file("server.pem"); |