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