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