1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation 4 #pragma once 5 6 #include "app.hpp" 7 #include "async_resp.hpp" 8 #include "error_messages.hpp" 9 #include "http_request.hpp" 10 #include "query.hpp" 11 #include "registries.hpp" 12 #include "registries/privilege_registry.hpp" 13 #include "registries_selector.hpp" 14 15 #include <boost/beast/http/verb.hpp> 16 #include <boost/url/format.hpp> 17 18 #include <array> 19 #include <format> 20 #include <functional> 21 #include <memory> 22 #include <optional> 23 #include <span> 24 #include <utility> 25 26 namespace redfish 27 { 28 29 inline void handleMessageRegistryFileCollectionGet( 30 crow::App& app, const crow::Request& req, 31 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 32 { 33 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 34 { 35 return; 36 } 37 // Collections don't include the static data added by SubRoute 38 // because it has a duplicate entry for members 39 40 asyncResp->res.jsonValue["@odata.type"] = 41 "#MessageRegistryFileCollection.MessageRegistryFileCollection"; 42 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Registries"; 43 asyncResp->res.jsonValue["Name"] = "MessageRegistryFile Collection"; 44 asyncResp->res.jsonValue["Description"] = 45 "Collection of MessageRegistryFiles"; 46 47 nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 48 49 static constexpr const auto registryFiles = std::to_array( 50 {"Base", "TaskEvent", "ResourceEvent", "OpenBMC", "Telemetry", 51 "HeartbeatEvent"}); 52 53 for (const char* memberName : registryFiles) 54 { 55 nlohmann::json::object_t member; 56 member["@odata.id"] = 57 boost::urls::format("/redfish/v1/Registries/{}", memberName); 58 members.emplace_back(std::move(member)); 59 } 60 asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 61 } 62 63 inline void requestRoutesMessageRegistryFileCollection(App& app) 64 { 65 /** 66 * Functions triggers appropriate requests on DBus 67 */ 68 BMCWEB_ROUTE(app, "/redfish/v1/Registries/") 69 .privileges(redfish::privileges::getMessageRegistryFileCollection) 70 .methods(boost::beast::http::verb::get)(std::bind_front( 71 handleMessageRegistryFileCollectionGet, std::ref(app))); 72 } 73 74 inline void handleMessageRoutesMessageRegistryFileGet( 75 crow::App& app, const crow::Request& req, 76 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 77 const std::string& registry) 78 { 79 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 80 { 81 return; 82 } 83 std::string dmtf = "DMTF "; 84 std::optional<registries::HeaderAndUrl> headerAndUrl = 85 registries::getRegistryHeaderAndUrlFromPrefix(registry); 86 87 if (!headerAndUrl) 88 { 89 messages::resourceNotFound(asyncResp->res, "MessageRegistryFile", 90 registry); 91 return; 92 } 93 if (registry == "OpenBMC") 94 { 95 dmtf.clear(); 96 } 97 const registries::Header& header = headerAndUrl->header; 98 const char* url = headerAndUrl->url; 99 100 asyncResp->res.jsonValue["@odata.id"] = 101 boost::urls::format("/redfish/v1/Registries/{}", registry); 102 asyncResp->res.jsonValue["@odata.type"] = 103 "#MessageRegistryFile.v1_1_0.MessageRegistryFile"; 104 asyncResp->res.jsonValue["Name"] = registry + " Message Registry File"; 105 asyncResp->res.jsonValue["Description"] = 106 dmtf + registry + " Message Registry File Location"; 107 asyncResp->res.jsonValue["Id"] = header.registryPrefix; 108 asyncResp->res.jsonValue["Registry"] = 109 std::format("{}.{}.{}", header.registryPrefix, header.versionMajor, 110 header.versionMinor); 111 nlohmann::json::array_t languages; 112 languages.emplace_back(header.language); 113 asyncResp->res.jsonValue["Languages@odata.count"] = languages.size(); 114 asyncResp->res.jsonValue["Languages"] = std::move(languages); 115 nlohmann::json::array_t locationMembers; 116 nlohmann::json::object_t location; 117 location["Language"] = header.language; 118 location["Uri"] = "/redfish/v1/Registries/" + registry + "/" + registry; 119 120 if (url != nullptr) 121 { 122 location["PublicationUri"] = url; 123 } 124 locationMembers.emplace_back(std::move(location)); 125 asyncResp->res.jsonValue["Location@odata.count"] = locationMembers.size(); 126 asyncResp->res.jsonValue["Location"] = std::move(locationMembers); 127 } 128 129 inline void requestRoutesMessageRegistryFile(App& app) 130 { 131 BMCWEB_ROUTE(app, "/redfish/v1/Registries/<str>/") 132 .privileges(redfish::privileges::getMessageRegistryFile) 133 .methods(boost::beast::http::verb::get)(std::bind_front( 134 handleMessageRoutesMessageRegistryFileGet, std::ref(app))); 135 } 136 137 inline void handleMessageRegistryGet( 138 crow::App& app, const crow::Request& req, 139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 140 const std::string& registry, const std::string& registryMatch) 141 142 { 143 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 144 { 145 return; 146 } 147 148 std::optional<registries::HeaderAndUrl> headerAndUrl = 149 registries::getRegistryHeaderAndUrlFromPrefix(registry); 150 if (!headerAndUrl) 151 { 152 messages::resourceNotFound(asyncResp->res, "MessageRegistryFile", 153 registry); 154 return; 155 } 156 157 const registries::Header& header = headerAndUrl->header; 158 if (registry != registryMatch) 159 { 160 messages::resourceNotFound(asyncResp->res, header.type, registryMatch); 161 return; 162 } 163 164 asyncResp->res.jsonValue["@Redfish.Copyright"] = header.copyright; 165 asyncResp->res.jsonValue["@odata.type"] = header.type; 166 asyncResp->res.jsonValue["Id"] = 167 std::format("{}.{}.{}.{}", header.registryPrefix, header.versionMajor, 168 header.versionMinor, header.versionPatch); 169 asyncResp->res.jsonValue["Name"] = header.name; 170 asyncResp->res.jsonValue["Language"] = header.language; 171 asyncResp->res.jsonValue["Description"] = header.description; 172 asyncResp->res.jsonValue["RegistryPrefix"] = header.registryPrefix; 173 asyncResp->res.jsonValue["RegistryVersion"] = 174 std::format("{}.{}.{}", header.versionMajor, header.versionMinor, 175 header.versionPatch); 176 asyncResp->res.jsonValue["OwningEntity"] = header.owningEntity; 177 178 nlohmann::json& messageObj = asyncResp->res.jsonValue["Messages"]; 179 180 // Go through the Message Registry and populate each Message 181 const std::span<const registries::MessageEntry> registryEntries = 182 registries::getRegistryFromPrefix(registry); 183 184 for (const registries::MessageEntry& message : registryEntries) 185 { 186 nlohmann::json& obj = messageObj[message.first]; 187 obj["Description"] = message.second.description; 188 obj["Message"] = message.second.message; 189 obj["Severity"] = message.second.messageSeverity; 190 obj["MessageSeverity"] = message.second.messageSeverity; 191 obj["NumberOfArgs"] = message.second.numberOfArgs; 192 obj["Resolution"] = message.second.resolution; 193 if (message.second.numberOfArgs > 0) 194 { 195 nlohmann::json& messageParamArray = obj["ParamTypes"]; 196 messageParamArray = nlohmann::json::array(); 197 for (const char* str : message.second.paramTypes) 198 { 199 if (str == nullptr) 200 { 201 break; 202 } 203 messageParamArray.push_back(str); 204 } 205 } 206 } 207 } 208 209 inline void requestRoutesMessageRegistry(App& app) 210 { 211 BMCWEB_ROUTE(app, "/redfish/v1/Registries/<str>/<str>/") 212 .privileges(redfish::privileges::getMessageRegistryFile) 213 .methods(boost::beast::http::verb::get)( 214 std::bind_front(handleMessageRegistryGet, std::ref(app))); 215 } 216 } // namespace redfish 217