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