Ed Tanous | 090ab8e | 2024-05-18 16:07:23 -0700 | [diff] [blame] | 1 | #pragma once |
| 2 | |
| 3 | #include "bmcweb_config.h" |
| 4 | |
| 5 | #include "app.hpp" |
| 6 | #include "async_resp.hpp" |
| 7 | #include "http_request.hpp" |
| 8 | #include "persistent_data.hpp" |
| 9 | #include "query.hpp" |
| 10 | #include "registries/privilege_registry.hpp" |
| 11 | #include "utils/systemd_utils.hpp" |
| 12 | |
| 13 | #include <tinyxml2.h> |
| 14 | |
| 15 | #include <nlohmann/json.hpp> |
| 16 | |
| 17 | namespace redfish |
| 18 | { |
| 19 | |
| 20 | inline std::string |
| 21 | getMetadataPieceForFile(const std::filesystem::path& filename) |
| 22 | { |
| 23 | std::string xml; |
| 24 | tinyxml2::XMLDocument doc; |
| 25 | std::string pathStr = filename.string(); |
| 26 | if (doc.LoadFile(pathStr.c_str()) != tinyxml2::XML_SUCCESS) |
| 27 | { |
| 28 | BMCWEB_LOG_ERROR("Failed to open XML file {}", pathStr); |
| 29 | return ""; |
| 30 | } |
| 31 | xml += std::format(" <edmx:Reference Uri=\"/redfish/v1/schema/{}\">\n", |
| 32 | filename.filename().string()); |
| 33 | // std::string edmx = "{http://docs.oasis-open.org/odata/ns/edmx}"; |
| 34 | // std::string edm = "{http://docs.oasis-open.org/odata/ns/edm}"; |
| 35 | const char* edmx = "edmx:Edmx"; |
| 36 | for (tinyxml2::XMLElement* edmxNode = doc.FirstChildElement(edmx); |
| 37 | edmxNode != nullptr; edmxNode = edmxNode->NextSiblingElement(edmx)) |
| 38 | { |
| 39 | const char* dataServices = "edmx:DataServices"; |
| 40 | for (tinyxml2::XMLElement* node = |
| 41 | edmxNode->FirstChildElement(dataServices); |
| 42 | node != nullptr; node = node->NextSiblingElement(dataServices)) |
| 43 | { |
| 44 | BMCWEB_LOG_DEBUG("Got data service for {}", pathStr); |
| 45 | const char* schemaTag = "Schema"; |
| 46 | for (tinyxml2::XMLElement* schemaNode = |
| 47 | node->FirstChildElement(schemaTag); |
| 48 | schemaNode != nullptr; |
| 49 | schemaNode = schemaNode->NextSiblingElement(schemaTag)) |
| 50 | { |
| 51 | std::string ns = schemaNode->Attribute("Namespace"); |
| 52 | // BMCWEB_LOG_DEBUG("Found namespace {}", ns); |
| 53 | std::string alias; |
| 54 | if (std::string_view(ns).starts_with("RedfishExtensions")) |
| 55 | { |
| 56 | alias = " Alias=\"Redfish\""; |
| 57 | } |
| 58 | xml += std::format( |
| 59 | " <edmx:Include Namespace=\"{}\"{}/>\n", ns, alias); |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | xml += " </edmx:Reference>\n"; |
| 64 | return xml; |
| 65 | } |
| 66 | |
| 67 | inline void |
| 68 | handleMetadataGet(App& /*app*/, const crow::Request& /*req*/, |
| 69 | const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| 70 | { |
| 71 | std::filesystem::path schema("/usr/share/www/redfish/v1/schema"); |
| 72 | std::error_code ec; |
| 73 | auto iter = std::filesystem::directory_iterator(schema, ec); |
| 74 | if (ec) |
| 75 | { |
| 76 | BMCWEB_LOG_ERROR("Failed to open XML folder {}", schema.string()); |
| 77 | asyncResp->res.result( |
| 78 | boost::beast::http::status::internal_server_error); |
| 79 | return; |
| 80 | } |
| 81 | std::string xml; |
| 82 | |
| 83 | xml += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; |
| 84 | xml += |
| 85 | "<edmx:Edmx xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\" Version=\"4.0\">\n"; |
| 86 | for (const auto& dirEntry : iter) |
| 87 | { |
| 88 | std::string path = dirEntry.path().filename(); |
| 89 | if (!std::string_view(path).ends_with("_v1.xml")) |
| 90 | { |
| 91 | continue; |
| 92 | } |
| 93 | std::string metadataPiece = getMetadataPieceForFile(dirEntry.path()); |
| 94 | if (metadataPiece.empty()) |
| 95 | { |
| 96 | asyncResp->res.result( |
| 97 | boost::beast::http::status::internal_server_error); |
| 98 | return; |
| 99 | } |
| 100 | xml += metadataPiece; |
| 101 | } |
| 102 | xml += " <edmx:DataServices>\n"; |
| 103 | xml += |
| 104 | " <Schema xmlns=\"http://docs.oasis-open.org/odata/ns/edm\" Namespace=\"Service\">\n"; |
| 105 | xml += |
| 106 | " <EntityContainer Name=\"Service\" Extends=\"ServiceRoot.v1_0_0.ServiceContainer\"/>\n"; |
| 107 | xml += " </Schema>\n"; |
| 108 | xml += " </edmx:DataServices>\n"; |
| 109 | xml += "</edmx:Edmx>\n"; |
| 110 | |
| 111 | asyncResp->res.addHeader(boost::beast::http::field::content_type, |
| 112 | "application/xml"); |
| 113 | asyncResp->res.write(std::move(xml)); |
| 114 | } |
| 115 | |
| 116 | inline void requestRoutesMetadata(App& app) |
| 117 | { |
| 118 | BMCWEB_ROUTE(app, "/redfish/v1/$metadata") |
| 119 | .methods(boost::beast::http::verb::get)( |
| 120 | std::bind_front(handleMetadataGet, std::ref(app))); |
| 121 | } |
| 122 | |
| 123 | } // namespace redfish |