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
handleMessageRegistryFileCollectionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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
requestRoutesMessageRegistryFileCollection(App & app)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
handleMessageRoutesMessageRegistryFileGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & registry)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
requestRoutesMessageRegistryFile(App & app)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
handleMessageRegistryGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & registry,const std::string & registryMatch)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
requestRoutesMessageRegistry(App & app)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