1 /*
2 Copyright (c) 2019 Intel Corporation
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8       http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 #pragma once
17 
18 #include "app.hpp"
19 #include "query.hpp"
20 #include "registries.hpp"
21 #include "registries/base_message_registry.hpp"
22 #include "registries/heartbeat_event_message_registry.hpp"
23 #include "registries/openbmc_message_registry.hpp"
24 #include "registries/privilege_registry.hpp"
25 #include "registries/resource_event_message_registry.hpp"
26 #include "registries/task_event_message_registry.hpp"
27 #include "registries/telemetry_message_registry.hpp"
28 
29 #include <boost/url/format.hpp>
30 
31 #include <array>
32 
33 namespace redfish
34 {
35 
36 inline void handleMessageRegistryFileCollectionGet(
37     crow::App& app, const crow::Request& req,
38     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
39 {
40     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
41     {
42         return;
43     }
44     // Collections don't include the static data added by SubRoute
45     // because it has a duplicate entry for members
46 
47     asyncResp->res.jsonValue["@odata.type"] =
48         "#MessageRegistryFileCollection.MessageRegistryFileCollection";
49     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Registries";
50     asyncResp->res.jsonValue["Name"] = "MessageRegistryFile Collection";
51     asyncResp->res.jsonValue["Description"] =
52         "Collection of MessageRegistryFiles";
53 
54     nlohmann::json& members = asyncResp->res.jsonValue["Members"];
55 
56     static constexpr const auto registryFiles = std::to_array(
57         {"Base", "TaskEvent", "ResourceEvent", "OpenBMC", "Telemetry",
58          "HeartbeatEvent"});
59 
60     for (const char* memberName : registryFiles)
61     {
62         nlohmann::json::object_t member;
63         member["@odata.id"] =
64             boost::urls::format("/redfish/v1/Registries/{}", memberName);
65         members.emplace_back(std::move(member));
66     }
67     asyncResp->res.jsonValue["Members@odata.count"] = members.size();
68 }
69 
70 inline void requestRoutesMessageRegistryFileCollection(App& app)
71 {
72     /**
73      * Functions triggers appropriate requests on DBus
74      */
75     BMCWEB_ROUTE(app, "/redfish/v1/Registries/")
76         .privileges(redfish::privileges::getMessageRegistryFileCollection)
77         .methods(boost::beast::http::verb::get)(std::bind_front(
78             handleMessageRegistryFileCollectionGet, std::ref(app)));
79 }
80 
81 inline void handleMessageRoutesMessageRegistryFileGet(
82     crow::App& app, const crow::Request& req,
83     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
84     const std::string& registry)
85 {
86     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
87     {
88         return;
89     }
90     const registries::Header* header = nullptr;
91     std::string dmtf = "DMTF ";
92     const char* url = nullptr;
93 
94     if (registry == "Base")
95     {
96         header = &registries::base::header;
97         url = registries::base::url;
98     }
99     else if (registry == "TaskEvent")
100     {
101         header = &registries::task_event::header;
102         url = registries::task_event::url;
103     }
104     else if (registry == "OpenBMC")
105     {
106         header = &registries::openbmc::header;
107         dmtf.clear();
108     }
109     else if (registry == "ResourceEvent")
110     {
111         header = &registries::resource_event::header;
112         url = registries::resource_event::url;
113     }
114     else if (registry == "Telemetry")
115     {
116         header = &registries::telemetry::header;
117         url = registries::telemetry::url;
118     }
119     else if (registry == "HeartbeatEvent")
120     {
121         header = &registries::heartbeat_event::header;
122         url = registries::heartbeat_event::url;
123     }
124     else
125     {
126         messages::resourceNotFound(asyncResp->res, "MessageRegistryFile",
127                                    registry);
128         return;
129     }
130 
131     asyncResp->res.jsonValue["@odata.id"] =
132         boost::urls::format("/redfish/v1/Registries/{}", registry);
133     asyncResp->res.jsonValue["@odata.type"] =
134         "#MessageRegistryFile.v1_1_0.MessageRegistryFile";
135     asyncResp->res.jsonValue["Name"] = registry + " Message Registry File";
136     asyncResp->res.jsonValue["Description"] =
137         dmtf + registry + " Message Registry File Location";
138     asyncResp->res.jsonValue["Id"] = header->registryPrefix;
139     asyncResp->res.jsonValue["Registry"] = header->id;
140     nlohmann::json::array_t languages;
141     languages.emplace_back(header->language);
142     asyncResp->res.jsonValue["Languages@odata.count"] = languages.size();
143     asyncResp->res.jsonValue["Languages"] = std::move(languages);
144     nlohmann::json::array_t locationMembers;
145     nlohmann::json::object_t location;
146     location["Language"] = header->language;
147     location["Uri"] = "/redfish/v1/Registries/" + registry + "/" + registry;
148 
149     if (url != nullptr)
150     {
151         location["PublicationUri"] = url;
152     }
153     locationMembers.emplace_back(std::move(location));
154     asyncResp->res.jsonValue["Location@odata.count"] = locationMembers.size();
155     asyncResp->res.jsonValue["Location"] = std::move(locationMembers);
156 }
157 
158 inline void requestRoutesMessageRegistryFile(App& app)
159 {
160     BMCWEB_ROUTE(app, "/redfish/v1/Registries/<str>/")
161         .privileges(redfish::privileges::getMessageRegistryFile)
162         .methods(boost::beast::http::verb::get)(std::bind_front(
163             handleMessageRoutesMessageRegistryFileGet, std::ref(app)));
164 }
165 
166 inline void handleMessageRegistryGet(
167     crow::App& app, const crow::Request& req,
168     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
169     const std::string& registry, const std::string& registryMatch)
170 
171 {
172     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
173     {
174         return;
175     }
176     const registries::Header* header = nullptr;
177     std::vector<const registries::MessageEntry*> registryEntries;
178     if (registry == "Base")
179     {
180         header = &registries::base::header;
181         for (const registries::MessageEntry& entry : registries::base::registry)
182         {
183             registryEntries.emplace_back(&entry);
184         }
185     }
186     else if (registry == "TaskEvent")
187     {
188         header = &registries::task_event::header;
189         for (const registries::MessageEntry& entry :
190              registries::task_event::registry)
191         {
192             registryEntries.emplace_back(&entry);
193         }
194     }
195     else if (registry == "OpenBMC")
196     {
197         header = &registries::openbmc::header;
198         for (const registries::MessageEntry& entry :
199              registries::openbmc::registry)
200         {
201             registryEntries.emplace_back(&entry);
202         }
203     }
204     else if (registry == "ResourceEvent")
205     {
206         header = &registries::resource_event::header;
207         for (const registries::MessageEntry& entry :
208              registries::resource_event::registry)
209         {
210             registryEntries.emplace_back(&entry);
211         }
212     }
213     else if (registry == "Telemetry")
214     {
215         header = &registries::telemetry::header;
216         for (const registries::MessageEntry& entry :
217              registries::telemetry::registry)
218         {
219             registryEntries.emplace_back(&entry);
220         }
221     }
222     else if (registry == "HeartbeatEvent")
223     {
224         header = &registries::heartbeat_event::header;
225         for (const registries::MessageEntry& entry :
226              registries::heartbeat_event::registry)
227         {
228             registryEntries.emplace_back(&entry);
229         }
230     }
231     else
232     {
233         messages::resourceNotFound(asyncResp->res, "MessageRegistryFile",
234                                    registry);
235         return;
236     }
237 
238     if (registry != registryMatch)
239     {
240         messages::resourceNotFound(asyncResp->res, header->type, registryMatch);
241         return;
242     }
243 
244     asyncResp->res.jsonValue["@Redfish.Copyright"] = header->copyright;
245     asyncResp->res.jsonValue["@odata.type"] = header->type;
246     asyncResp->res.jsonValue["Id"] = header->id;
247     asyncResp->res.jsonValue["Name"] = header->name;
248     asyncResp->res.jsonValue["Language"] = header->language;
249     asyncResp->res.jsonValue["Description"] = header->description;
250     asyncResp->res.jsonValue["RegistryPrefix"] = header->registryPrefix;
251     asyncResp->res.jsonValue["RegistryVersion"] = header->registryVersion;
252     asyncResp->res.jsonValue["OwningEntity"] = header->owningEntity;
253 
254     nlohmann::json& messageObj = asyncResp->res.jsonValue["Messages"];
255 
256     // Go through the Message Registry and populate each Message
257     for (const registries::MessageEntry* message : registryEntries)
258     {
259         nlohmann::json& obj = messageObj[message->first];
260         obj["Description"] = message->second.description;
261         obj["Message"] = message->second.message;
262         obj["Severity"] = message->second.messageSeverity;
263         obj["MessageSeverity"] = message->second.messageSeverity;
264         obj["NumberOfArgs"] = message->second.numberOfArgs;
265         obj["Resolution"] = message->second.resolution;
266         if (message->second.numberOfArgs > 0)
267         {
268             nlohmann::json& messageParamArray = obj["ParamTypes"];
269             messageParamArray = nlohmann::json::array();
270             for (const char* str : message->second.paramTypes)
271             {
272                 if (str == nullptr)
273                 {
274                     break;
275                 }
276                 messageParamArray.push_back(str);
277             }
278         }
279     }
280 }
281 
282 inline void requestRoutesMessageRegistry(App& app)
283 {
284     BMCWEB_ROUTE(app, "/redfish/v1/Registries/<str>/<str>/")
285         .privileges(redfish::privileges::getMessageRegistryFile)
286         .methods(boost::beast::http::verb::get)(
287             std::bind_front(handleMessageRegistryGet, std::ref(app)));
288 }
289 } // namespace redfish
290