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