xref: /openbmc/bmcweb/redfish-core/lib/systems_logservices_postcodes.hpp (revision 177612aaa0633cf9d5aef0b763a43135cf552d9b)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #pragma once
4 
5 #include "bmcweb_config.h"
6 
7 #include "app.hpp"
8 #include "async_resp.hpp"
9 #include "dbus_utility.hpp"
10 #include "error_messages.hpp"
11 #include "generated/enums/log_service.hpp"
12 #include "http_request.hpp"
13 #include "http_utility.hpp"
14 #include "logging.hpp"
15 #include "query.hpp"
16 #include "registries.hpp"
17 #include "registries/privilege_registry.hpp"
18 #include "str_utility.hpp"
19 #include "utility.hpp"
20 #include "utils/hex_utils.hpp"
21 #include "utils/query_param.hpp"
22 #include "utils/time_utils.hpp"
23 
24 #include <asm-generic/errno.h>
25 
26 #include <boost/beast/http/field.hpp>
27 #include <boost/beast/http/status.hpp>
28 #include <boost/beast/http/verb.hpp>
29 #include <boost/container/flat_map.hpp>
30 #include <boost/url/format.hpp>
31 
32 #include <algorithm>
33 #include <array>
34 #include <charconv>
35 #include <cstddef>
36 #include <cstdint>
37 #include <format>
38 #include <functional>
39 #include <iomanip>
40 #include <ios>
41 #include <memory>
42 #include <sstream>
43 #include <string>
44 #include <string_view>
45 #include <system_error>
46 #include <tuple>
47 #include <utility>
48 #include <vector>
49 
50 namespace redfish
51 {
52 
handleSystemsLogServicesPostCodesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)53 inline void handleSystemsLogServicesPostCodesGet(
54     App& app, const crow::Request& req,
55     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
56     const std::string& systemName)
57 {
58     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
59     {
60         return;
61     }
62     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
63     {
64         // Option currently returns no systems.  TBD
65         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
66                                    systemName);
67         return;
68     }
69     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
70     {
71         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
72                                    systemName);
73         return;
74     }
75     asyncResp->res.jsonValue["@odata.id"] =
76         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
77                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
78     asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
79     asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
80     asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
81     asyncResp->res.jsonValue["Id"] = "PostCodes";
82     asyncResp->res.jsonValue["OverWritePolicy"] =
83         log_service::OverWritePolicy::WrapsWhenFull;
84     asyncResp->res.jsonValue["Entries"]["@odata.id"] =
85         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
86                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
87 
88     std::pair<std::string, std::string> redfishDateTimeOffset =
89         redfish::time_utils::getDateTimeOffsetNow();
90     asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
91     asyncResp->res.jsonValue["DateTimeLocalOffset"] =
92         redfishDateTimeOffset.second;
93 
94     asyncResp->res
95         .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format(
96         "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
97         BMCWEB_REDFISH_SYSTEM_URI_NAME);
98 }
99 
handleSystemsLogServicesPostCodesPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)100 inline void handleSystemsLogServicesPostCodesPost(
101     App& app, const crow::Request& req,
102     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103     const std::string& systemName)
104 {
105     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
106     {
107         return;
108     }
109     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
110     {
111         // Option currently returns no systems.  TBD
112         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
113                                    systemName);
114         return;
115     }
116     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
117     {
118         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
119                                    systemName);
120         return;
121     }
122     BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
123 
124     // Make call to post-code service to request clear all
125     dbus::utility::async_method_call(
126         asyncResp,
127         [asyncResp](const boost::system::error_code& ec) {
128             if (ec)
129             {
130                 // TODO Handle for specific error code
131                 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
132                                  ec);
133                 asyncResp->res.result(
134                     boost::beast::http::status::internal_server_error);
135                 messages::internalError(asyncResp->res);
136                 return;
137             }
138             messages::success(asyncResp->res);
139         },
140         "xyz.openbmc_project.State.Boot.PostCode0",
141         "/xyz/openbmc_project/State/Boot/PostCode0",
142         "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
143 }
144 
145 /**
146  * @brief Parse post code ID and get the current value and index value
147  *        eg: postCodeID=B1-2, currentValue=1, index=2
148  *
149  * @param[in]  postCodeID     Post Code ID
150  * @param[out] currentValue   Current value
151  * @param[out] index          Index value
152  *
153  * @return bool true if the parsing is successful, false the parsing fails
154  */
parsePostCode(std::string_view postCodeID,uint64_t & currentValue,uint16_t & index)155 inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
156                           uint16_t& index)
157 {
158     std::vector<std::string> split;
159     bmcweb::split(split, postCodeID, '-');
160     if (split.size() != 2)
161     {
162         return false;
163     }
164     std::string_view postCodeNumber = split[0];
165     if (postCodeNumber.size() < 2)
166     {
167         return false;
168     }
169     if (postCodeNumber[0] != 'B')
170     {
171         return false;
172     }
173     postCodeNumber.remove_prefix(1);
174     auto [ptrIndex, ecIndex] =
175         std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index);
176     if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
177     {
178         return false;
179     }
180 
181     std::string_view postCodeIndex = split[1];
182 
183     auto [ptrValue, ecValue] = std::from_chars(
184         postCodeIndex.begin(), postCodeIndex.end(), currentValue);
185 
186     return ptrValue == postCodeIndex.end() && ecValue == std::errc();
187 }
188 
fillPostCodeEntry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::container::flat_map<uint64_t,std::tuple<std::vector<uint8_t>,std::vector<uint8_t>>> & postcode,const uint16_t bootIndex,const uint64_t codeIndex=0,const uint64_t skip=0,const uint64_t top=0)189 static bool fillPostCodeEntry(
190     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191     const boost::container::flat_map<
192         uint64_t, std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>>&
193         postcode,
194     const uint16_t bootIndex, const uint64_t codeIndex = 0,
195     const uint64_t skip = 0, const uint64_t top = 0)
196 {
197     // Get the Message from the MessageRegistry
198     const registries::Message* message =
199         registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
200     if (message == nullptr)
201     {
202         BMCWEB_LOG_ERROR("Couldn't find known message?");
203         return false;
204     }
205     uint64_t currentCodeIndex = 0;
206     uint64_t firstCodeTimeUs = 0;
207     for (const std::pair<uint64_t, std::tuple<std::vector<uint8_t>,
208                                               std::vector<uint8_t>>>& code :
209          postcode)
210     {
211         currentCodeIndex++;
212         std::string postcodeEntryID =
213             "B" + std::to_string(bootIndex) + "-" +
214             std::to_string(currentCodeIndex); // 1 based index in EntryID string
215 
216         uint64_t usecSinceEpoch = code.first;
217         uint64_t usTimeOffset = 0;
218 
219         if (1 == currentCodeIndex)
220         { // already incremented
221             firstCodeTimeUs = code.first;
222         }
223         else
224         {
225             usTimeOffset = code.first - firstCodeTimeUs;
226         }
227 
228         // skip if no specific codeIndex is specified and currentCodeIndex does
229         // not fall between top and skip
230         if ((codeIndex == 0) &&
231             (currentCodeIndex <= skip || currentCodeIndex > top))
232         {
233             continue;
234         }
235 
236         // skip if a specific codeIndex is specified and does not match the
237         // currentIndex
238         if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
239         {
240             // This is done for simplicity. 1st entry is needed to calculate
241             // time offset. To improve efficiency, one can get to the entry
242             // directly (possibly with flatmap's nth method)
243             continue;
244         }
245 
246         // currentCodeIndex is within top and skip or equal to specified code
247         // index
248 
249         // Get the Created time from the timestamp
250         std::string entryTimeStr;
251         entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
252 
253         // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
254         std::ostringstream timeOffsetStr;
255         // Set Fixed -Point Notation
256         timeOffsetStr << std::fixed;
257         // Set precision to 4 digits
258         timeOffsetStr << std::setprecision(4);
259         // Add double to stream
260         timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
261 
262         std::string bootIndexStr = std::to_string(bootIndex);
263         std::string timeOffsetString = timeOffsetStr.str();
264         std::string hexCodeStr =
265             "0x" + bytesToHexString(std::get<0>(code.second));
266 
267         std::array<std::string_view, 3> messageArgs = {
268             bootIndexStr, timeOffsetString, hexCodeStr};
269 
270         std::string msg =
271             redfish::registries::fillMessageArgs(messageArgs, message->message);
272         if (msg.empty())
273         {
274             messages::internalError(asyncResp->res);
275             return false;
276         }
277 
278         // Get Severity template from message registry
279         std::string severity;
280         if (message != nullptr)
281         {
282             severity = message->messageSeverity;
283         }
284 
285         // Format entry
286         nlohmann::json::object_t bmcLogEntry;
287         bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
288         bmcLogEntry["@odata.id"] = boost::urls::format(
289             "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
290             BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
291         bmcLogEntry["Name"] = "POST Code Log Entry";
292         bmcLogEntry["Id"] = postcodeEntryID;
293         bmcLogEntry["Message"] = std::move(msg);
294         bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
295         bmcLogEntry["MessageArgs"] = messageArgs;
296         bmcLogEntry["EntryType"] = "Event";
297         bmcLogEntry["Severity"] = std::move(severity);
298         bmcLogEntry["Created"] = entryTimeStr;
299         if (!std::get<1>(code.second).empty())
300         {
301             bmcLogEntry["AdditionalDataURI"] =
302                 std::format(
303                     "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
304                     BMCWEB_REDFISH_SYSTEM_URI_NAME) +
305                 postcodeEntryID + "/attachment";
306         }
307 
308         // codeIndex is only specified when querying single entry, return only
309         // that entry in this case
310         if (codeIndex != 0)
311         {
312             asyncResp->res.jsonValue.update(bmcLogEntry);
313             return true;
314         }
315 
316         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
317         logEntryArray.emplace_back(std::move(bmcLogEntry));
318     }
319 
320     // Return value is always false when querying multiple entries
321     return false;
322 }
323 
getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & entryId)324 inline void getPostCodeForEntry(
325     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
326     const std::string& entryId)
327 {
328     uint16_t bootIndex = 0;
329     uint64_t codeIndex = 0;
330     if (!parsePostCode(entryId, codeIndex, bootIndex))
331     {
332         // Requested ID was not found
333         messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
334         return;
335     }
336 
337     if (bootIndex == 0 || codeIndex == 0)
338     {
339         // 0 is an invalid index
340         messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
341         return;
342     }
343 
344     dbus::utility::async_method_call(
345         asyncResp,
346         [asyncResp, entryId, bootIndex,
347          codeIndex](const boost::system::error_code& ec,
348                     const boost::container::flat_map<
349                         uint64_t, std::tuple<std::vector<uint8_t>,
350                                              std::vector<uint8_t>>>& postcode) {
351             if (ec)
352             {
353                 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
354                 messages::internalError(asyncResp->res);
355                 return;
356             }
357 
358             if (postcode.empty())
359             {
360                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
361                 return;
362             }
363 
364             if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
365             {
366                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
367                 return;
368             }
369         },
370         "xyz.openbmc_project.State.Boot.PostCode0",
371         "/xyz/openbmc_project/State/Boot/PostCode0",
372         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
373         bootIndex);
374 }
375 
getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const uint16_t bootIndex,const uint16_t bootCount,const uint64_t entryCount,size_t skip,size_t top)376 inline void getPostCodeForBoot(
377     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
378     const uint16_t bootIndex, const uint16_t bootCount,
379     const uint64_t entryCount, size_t skip, size_t top)
380 {
381     dbus::utility::async_method_call(
382         asyncResp,
383         [asyncResp, bootIndex, bootCount, entryCount, skip,
384          top](const boost::system::error_code& ec,
385               const boost::container::flat_map<
386                   uint64_t, std::tuple<std::vector<uint8_t>,
387                                        std::vector<uint8_t>>>& postcode) {
388             if (ec)
389             {
390                 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
391                 messages::internalError(asyncResp->res);
392                 return;
393             }
394 
395             uint64_t endCount = entryCount;
396             if (!postcode.empty())
397             {
398                 endCount = entryCount + postcode.size();
399                 if (skip < endCount && (top + skip) > entryCount)
400                 {
401                     uint64_t thisBootSkip =
402                         std::max(static_cast<uint64_t>(skip), entryCount) -
403                         entryCount;
404                     uint64_t thisBootTop =
405                         std::min(static_cast<uint64_t>(top + skip), endCount) -
406                         entryCount;
407 
408                     fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
409                                       thisBootSkip, thisBootTop);
410                 }
411                 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
412             }
413 
414             // continue to previous bootIndex
415             if (bootIndex < bootCount)
416             {
417                 getPostCodeForBoot(asyncResp,
418                                    static_cast<uint16_t>(bootIndex + 1),
419                                    bootCount, endCount, skip, top);
420             }
421             else if (skip + top < endCount)
422             {
423                 asyncResp->res.jsonValue["Members@odata.nextLink"] =
424                     std::format(
425                         "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
426                         BMCWEB_REDFISH_SYSTEM_URI_NAME) +
427                     std::to_string(skip + top);
428             }
429         },
430         "xyz.openbmc_project.State.Boot.PostCode0",
431         "/xyz/openbmc_project/State/Boot/PostCode0",
432         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
433         bootIndex);
434 }
435 
getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,size_t skip,size_t top)436 inline void getCurrentBootNumber(
437     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, size_t skip,
438     size_t top)
439 {
440     uint64_t entryCount = 0;
441     dbus::utility::getProperty<uint16_t>(
442         "xyz.openbmc_project.State.Boot.PostCode0",
443         "/xyz/openbmc_project/State/Boot/PostCode0",
444         "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
445         [asyncResp, entryCount, skip,
446          top](const boost::system::error_code& ec, const uint16_t bootCount) {
447             if (ec)
448             {
449                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
450                 messages::internalError(asyncResp->res);
451                 return;
452             }
453             getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
454         });
455 }
456 
handleSystemsLogServicesPostCodesEntriesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)457 inline void handleSystemsLogServicesPostCodesEntriesGet(
458     App& app, const crow::Request& req,
459     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
460     const std::string& systemName)
461 {
462     query_param::QueryCapabilities capabilities = {
463         .canDelegateTop = true,
464         .canDelegateSkip = true,
465     };
466     query_param::Query delegatedQuery;
467     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
468                                                   delegatedQuery, capabilities))
469     {
470         return;
471     }
472     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
473     {
474         // Option currently returns no systems.  TBD
475         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
476                                    systemName);
477         return;
478     }
479 
480     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
481     {
482         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
483                                    systemName);
484         return;
485     }
486     asyncResp->res.jsonValue["@odata.type"] =
487         "#LogEntryCollection.LogEntryCollection";
488     asyncResp->res.jsonValue["@odata.id"] =
489         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
490                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
491     asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
492     asyncResp->res.jsonValue["Description"] =
493         "Collection of POST Code Log Entries";
494     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
495     asyncResp->res.jsonValue["Members@odata.count"] = 0;
496     size_t skip = delegatedQuery.skip.value_or(0);
497     size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
498     getCurrentBootNumber(asyncResp, skip, top);
499 }
500 
handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & postCodeID)501 inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(
502     App& app, const crow::Request& req,
503     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
504     const std::string& systemName, const std::string& postCodeID)
505 {
506     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
507     {
508         return;
509     }
510     if (!http_helpers::isContentTypeAllowed(
511             req.getHeaderValue("Accept"),
512             http_helpers::ContentType::OctetStream, true))
513     {
514         asyncResp->res.result(boost::beast::http::status::bad_request);
515         return;
516     }
517     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
518     {
519         // Option currently returns no systems.  TBD
520         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
521                                    systemName);
522         return;
523     }
524     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
525     {
526         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
527                                    systemName);
528         return;
529     }
530 
531     uint64_t currentValue = 0;
532     uint16_t index = 0;
533     if (!parsePostCode(postCodeID, currentValue, index))
534     {
535         messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
536         return;
537     }
538 
539     dbus::utility::async_method_call(
540         asyncResp,
541         [asyncResp, postCodeID, currentValue](
542             const boost::system::error_code& ec,
543             const std::vector<std::tuple<std::vector<uint8_t>,
544                                          std::vector<uint8_t>>>& postcodes) {
545             if (ec.value() == EBADR)
546             {
547                 messages::resourceNotFound(asyncResp->res, "LogEntry",
548                                            postCodeID);
549                 return;
550             }
551             if (ec)
552             {
553                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
554                 messages::internalError(asyncResp->res);
555                 return;
556             }
557 
558             size_t value = static_cast<size_t>(currentValue) - 1;
559             if (value == std::string::npos || postcodes.size() < currentValue)
560             {
561                 BMCWEB_LOG_WARNING("Wrong currentValue value");
562                 messages::resourceNotFound(asyncResp->res, "LogEntry",
563                                            postCodeID);
564                 return;
565             }
566 
567             const auto& [tID, c] = postcodes[value];
568             if (c.empty())
569             {
570                 BMCWEB_LOG_WARNING("No found post code data");
571                 messages::resourceNotFound(asyncResp->res, "LogEntry",
572                                            postCodeID);
573                 return;
574             }
575             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
576             const char* d = reinterpret_cast<const char*>(c.data());
577             std::string_view strData(d, c.size());
578 
579             asyncResp->res.addHeader(boost::beast::http::field::content_type,
580                                      "application/octet-stream");
581             asyncResp->res.addHeader(
582                 boost::beast::http::field::content_transfer_encoding, "Base64");
583             asyncResp->res.write(crow::utility::base64encode(strData));
584         },
585         "xyz.openbmc_project.State.Boot.PostCode0",
586         "/xyz/openbmc_project/State/Boot/PostCode0",
587         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
588 }
589 
handleSystemsLogServicesPostCodesEntriesEntryGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & targetID)590 inline void handleSystemsLogServicesPostCodesEntriesEntryGet(
591     App& app, const crow::Request& req,
592     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
593     const std::string& systemName, const std::string& targetID)
594 {
595     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
596     {
597         return;
598     }
599     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
600     {
601         // Option currently returns no systems.  TBD
602         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
603                                    systemName);
604         return;
605     }
606     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
607     {
608         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
609                                    systemName);
610         return;
611     }
612 
613     getPostCodeForEntry(asyncResp, targetID);
614 }
615 
requestRoutesSystemsLogServicesPostCode(App & app)616 inline void requestRoutesSystemsLogServicesPostCode(App& app)
617 {
618     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
619         .privileges(redfish::privileges::getLogService)
620         .methods(boost::beast::http::verb::get)(std::bind_front(
621             handleSystemsLogServicesPostCodesGet, std::ref(app)));
622 
623     BMCWEB_ROUTE(
624         app,
625         "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
626         // The following privilege is correct; we need "SubordinateOverrides"
627         // before we can automate it.
628         .privileges({{"ConfigureComponents"}})
629         .methods(boost::beast::http::verb::post)(std::bind_front(
630             handleSystemsLogServicesPostCodesPost, std::ref(app)));
631 
632     BMCWEB_ROUTE(app,
633                  "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
634         .privileges(redfish::privileges::getLogEntryCollection)
635         .methods(boost::beast::http::verb::get)(std::bind_front(
636             handleSystemsLogServicesPostCodesEntriesGet, std::ref(app)));
637 
638     BMCWEB_ROUTE(
639         app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
640         .privileges(redfish::privileges::getLogEntry)
641         .methods(boost::beast::http::verb::get)(std::bind_front(
642             handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app)));
643 
644     BMCWEB_ROUTE(
645         app,
646         "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
647         .privileges(redfish::privileges::getLogEntry)
648         .methods(boost::beast::http::verb::get)(std::bind_front(
649             handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet,
650             std::ref(app)));
651 }
652 } // namespace redfish
653