blob: df02ad606de7266bb3d2be0d5721a8efaf0caf53 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Ed Tanous090ab8e2024-05-18 16:07:23 -07003#pragma once
4
Ed Tanous090ab8e2024-05-18 16:07:23 -07005#include "app.hpp"
6#include "async_resp.hpp"
7#include "http_request.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08008#include "logging.hpp"
Ed Tanous090ab8e2024-05-18 16:07:23 -07009
10#include <tinyxml2.h>
11
Ed Tanousd7857202025-01-28 15:32:26 -080012#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 Tanous090ab8e2024-05-18 16:07:23 -070023
24namespace redfish
25{
26
Patrick Williams504af5a2025-02-03 14:29:03 -050027inline std::string getMetadataPieceForFile(
28 const std::filesystem::path& filename)
Ed Tanous090ab8e2024-05-18 16:07:23 -070029{
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 Williams504af5a2025-02-03 14:29:03 -050074inline void handleMetadataGet(
75 App& /*app*/, const crow::Request& /*req*/,
76 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous090ab8e2024-05-18 16:07:23 -070077{
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
123inline void requestRoutesMetadata(App& app)
124{
Ed Tanous90089752024-11-20 13:27:22 -0800125 BMCWEB_ROUTE(app, "/redfish/v1/$metadata/")
Ed Tanous090ab8e2024-05-18 16:07:23 -0700126 .methods(boost::beast::http::verb::get)(
127 std::bind_front(handleMetadataGet, std::ref(app)));
128}
129
130} // namespace redfish