blob: 4d8b1312c75ab4c78f9b7deda9368c7d1457bf6e [file] [log] [blame]
Ed Tanous090ab8e2024-05-18 16:07:23 -07001#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
17namespace redfish
18{
19
20inline 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
67inline 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
116inline 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