blob: 4d8b1312c75ab4c78f9b7deda9368c7d1457bf6e [file] [log] [blame]
#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