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