1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3090ab8e1SEd Tanous #pragma once 4090ab8e1SEd Tanous 5090ab8e1SEd Tanous #include "bmcweb_config.h" 6090ab8e1SEd Tanous 7090ab8e1SEd Tanous #include "app.hpp" 8090ab8e1SEd Tanous #include "async_resp.hpp" 9090ab8e1SEd Tanous #include "http_request.hpp" 10090ab8e1SEd Tanous #include "persistent_data.hpp" 11090ab8e1SEd Tanous #include "query.hpp" 12090ab8e1SEd Tanous #include "registries/privilege_registry.hpp" 13090ab8e1SEd Tanous #include "utils/systemd_utils.hpp" 14090ab8e1SEd Tanous 15090ab8e1SEd Tanous #include <tinyxml2.h> 16090ab8e1SEd Tanous 17090ab8e1SEd Tanous #include <nlohmann/json.hpp> 18090ab8e1SEd Tanous 19090ab8e1SEd Tanous namespace redfish 20090ab8e1SEd Tanous { 21090ab8e1SEd Tanous 22090ab8e1SEd Tanous inline std::string 23090ab8e1SEd Tanous getMetadataPieceForFile(const std::filesystem::path& filename) 24090ab8e1SEd Tanous { 25090ab8e1SEd Tanous std::string xml; 26090ab8e1SEd Tanous tinyxml2::XMLDocument doc; 27090ab8e1SEd Tanous std::string pathStr = filename.string(); 28090ab8e1SEd Tanous if (doc.LoadFile(pathStr.c_str()) != tinyxml2::XML_SUCCESS) 29090ab8e1SEd Tanous { 30090ab8e1SEd Tanous BMCWEB_LOG_ERROR("Failed to open XML file {}", pathStr); 31090ab8e1SEd Tanous return ""; 32090ab8e1SEd Tanous } 33090ab8e1SEd Tanous xml += std::format(" <edmx:Reference Uri=\"/redfish/v1/schema/{}\">\n", 34090ab8e1SEd Tanous filename.filename().string()); 35090ab8e1SEd Tanous // std::string edmx = "{http://docs.oasis-open.org/odata/ns/edmx}"; 36090ab8e1SEd Tanous // std::string edm = "{http://docs.oasis-open.org/odata/ns/edm}"; 37090ab8e1SEd Tanous const char* edmx = "edmx:Edmx"; 38090ab8e1SEd Tanous for (tinyxml2::XMLElement* edmxNode = doc.FirstChildElement(edmx); 39090ab8e1SEd Tanous edmxNode != nullptr; edmxNode = edmxNode->NextSiblingElement(edmx)) 40090ab8e1SEd Tanous { 41090ab8e1SEd Tanous const char* dataServices = "edmx:DataServices"; 42090ab8e1SEd Tanous for (tinyxml2::XMLElement* node = 43090ab8e1SEd Tanous edmxNode->FirstChildElement(dataServices); 44090ab8e1SEd Tanous node != nullptr; node = node->NextSiblingElement(dataServices)) 45090ab8e1SEd Tanous { 46090ab8e1SEd Tanous BMCWEB_LOG_DEBUG("Got data service for {}", pathStr); 47090ab8e1SEd Tanous const char* schemaTag = "Schema"; 48090ab8e1SEd Tanous for (tinyxml2::XMLElement* schemaNode = 49090ab8e1SEd Tanous node->FirstChildElement(schemaTag); 50090ab8e1SEd Tanous schemaNode != nullptr; 51090ab8e1SEd Tanous schemaNode = schemaNode->NextSiblingElement(schemaTag)) 52090ab8e1SEd Tanous { 53090ab8e1SEd Tanous std::string ns = schemaNode->Attribute("Namespace"); 54090ab8e1SEd Tanous // BMCWEB_LOG_DEBUG("Found namespace {}", ns); 55090ab8e1SEd Tanous std::string alias; 56090ab8e1SEd Tanous if (std::string_view(ns).starts_with("RedfishExtensions")) 57090ab8e1SEd Tanous { 58090ab8e1SEd Tanous alias = " Alias=\"Redfish\""; 59090ab8e1SEd Tanous } 60090ab8e1SEd Tanous xml += std::format( 61090ab8e1SEd Tanous " <edmx:Include Namespace=\"{}\"{}/>\n", ns, alias); 62090ab8e1SEd Tanous } 63090ab8e1SEd Tanous } 64090ab8e1SEd Tanous } 65090ab8e1SEd Tanous xml += " </edmx:Reference>\n"; 66090ab8e1SEd Tanous return xml; 67090ab8e1SEd Tanous } 68090ab8e1SEd Tanous 69090ab8e1SEd Tanous inline void 70090ab8e1SEd Tanous handleMetadataGet(App& /*app*/, const crow::Request& /*req*/, 71090ab8e1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 72090ab8e1SEd Tanous { 73090ab8e1SEd Tanous std::filesystem::path schema("/usr/share/www/redfish/v1/schema"); 74090ab8e1SEd Tanous std::error_code ec; 75090ab8e1SEd Tanous auto iter = std::filesystem::directory_iterator(schema, ec); 76090ab8e1SEd Tanous if (ec) 77090ab8e1SEd Tanous { 78090ab8e1SEd Tanous BMCWEB_LOG_ERROR("Failed to open XML folder {}", schema.string()); 79090ab8e1SEd Tanous asyncResp->res.result( 80090ab8e1SEd Tanous boost::beast::http::status::internal_server_error); 81090ab8e1SEd Tanous return; 82090ab8e1SEd Tanous } 83090ab8e1SEd Tanous std::string xml; 84090ab8e1SEd Tanous 85090ab8e1SEd Tanous xml += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 86090ab8e1SEd Tanous xml += 87090ab8e1SEd Tanous "<edmx:Edmx xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\" Version=\"4.0\">\n"; 88090ab8e1SEd Tanous for (const auto& dirEntry : iter) 89090ab8e1SEd Tanous { 90090ab8e1SEd Tanous std::string path = dirEntry.path().filename(); 91090ab8e1SEd Tanous if (!std::string_view(path).ends_with("_v1.xml")) 92090ab8e1SEd Tanous { 93090ab8e1SEd Tanous continue; 94090ab8e1SEd Tanous } 95090ab8e1SEd Tanous std::string metadataPiece = getMetadataPieceForFile(dirEntry.path()); 96090ab8e1SEd Tanous if (metadataPiece.empty()) 97090ab8e1SEd Tanous { 98090ab8e1SEd Tanous asyncResp->res.result( 99090ab8e1SEd Tanous boost::beast::http::status::internal_server_error); 100090ab8e1SEd Tanous return; 101090ab8e1SEd Tanous } 102090ab8e1SEd Tanous xml += metadataPiece; 103090ab8e1SEd Tanous } 104090ab8e1SEd Tanous xml += " <edmx:DataServices>\n"; 105090ab8e1SEd Tanous xml += 106090ab8e1SEd Tanous " <Schema xmlns=\"http://docs.oasis-open.org/odata/ns/edm\" Namespace=\"Service\">\n"; 107090ab8e1SEd Tanous xml += 108090ab8e1SEd Tanous " <EntityContainer Name=\"Service\" Extends=\"ServiceRoot.v1_0_0.ServiceContainer\"/>\n"; 109090ab8e1SEd Tanous xml += " </Schema>\n"; 110090ab8e1SEd Tanous xml += " </edmx:DataServices>\n"; 111090ab8e1SEd Tanous xml += "</edmx:Edmx>\n"; 112090ab8e1SEd Tanous 113090ab8e1SEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type, 114090ab8e1SEd Tanous "application/xml"); 115090ab8e1SEd Tanous asyncResp->res.write(std::move(xml)); 116090ab8e1SEd Tanous } 117090ab8e1SEd Tanous 118090ab8e1SEd Tanous inline void requestRoutesMetadata(App& app) 119090ab8e1SEd Tanous { 1209008975eSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/$metadata/") 121090ab8e1SEd Tanous .methods(boost::beast::http::verb::get)( 122090ab8e1SEd Tanous std::bind_front(handleMetadataGet, std::ref(app))); 123090ab8e1SEd Tanous } 124090ab8e1SEd Tanous 125090ab8e1SEd Tanous } // namespace redfish 126