xref: /openbmc/bmcweb/redfish-core/lib/systems_logservices_postcodes.hpp (revision 504af5a0568171b72caf13234cc81380b261fa21)
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_singleton.hpp"
10 #include "dbus_utility.hpp"
11 #include "error_messages.hpp"
12 #include "generated/enums/log_service.hpp"
13 #include "http_request.hpp"
14 #include "http_utility.hpp"
15 #include "logging.hpp"
16 #include "query.hpp"
17 #include "registries.hpp"
18 #include "registries/privilege_registry.hpp"
19 #include "str_utility.hpp"
20 #include "utility.hpp"
21 #include "utils/hex_utils.hpp"
22 #include "utils/query_param.hpp"
23 #include "utils/time_utils.hpp"
24 
25 #include <asm-generic/errno.h>
26 
27 #include <boost/beast/http/field.hpp>
28 #include <boost/beast/http/status.hpp>
29 #include <boost/beast/http/verb.hpp>
30 #include <boost/container/flat_map.hpp>
31 #include <boost/url/format.hpp>
32 
33 #include <algorithm>
34 #include <array>
35 #include <charconv>
36 #include <cstddef>
37 #include <cstdint>
38 #include <format>
39 #include <functional>
40 #include <iomanip>
41 #include <ios>
42 #include <memory>
43 #include <sstream>
44 #include <string>
45 #include <string_view>
46 #include <system_error>
47 #include <tuple>
48 #include <utility>
49 #include <vector>
50 
51 namespace redfish
52 {
53 
handleSystemsLogServicesPostCodesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)54 inline void handleSystemsLogServicesPostCodesGet(
55     App& app, const crow::Request& req,
56     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
57     const std::string& systemName)
58 {
59     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
60     {
61         return;
62     }
63     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
64     {
65         // Option currently returns no systems.  TBD
66         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
67                                    systemName);
68         return;
69     }
70     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
71     {
72         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
73                                    systemName);
74         return;
75     }
76     asyncResp->res.jsonValue["@odata.id"] =
77         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
78                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
79     asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
80     asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
81     asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
82     asyncResp->res.jsonValue["Id"] = "PostCodes";
83     asyncResp->res.jsonValue["OverWritePolicy"] =
84         log_service::OverWritePolicy::WrapsWhenFull;
85     asyncResp->res.jsonValue["Entries"]["@odata.id"] =
86         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
87                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
88 
89     std::pair<std::string, std::string> redfishDateTimeOffset =
90         redfish::time_utils::getDateTimeOffsetNow();
91     asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
92     asyncResp->res.jsonValue["DateTimeLocalOffset"] =
93         redfishDateTimeOffset.second;
94 
95     asyncResp->res
96         .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format(
97         "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
98         BMCWEB_REDFISH_SYSTEM_URI_NAME);
99 }
100 
handleSystemsLogServicesPostCodesPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)101 inline void handleSystemsLogServicesPostCodesPost(
102     App& app, const crow::Request& req,
103     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
104     const std::string& systemName)
105 {
106     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
107     {
108         return;
109     }
110     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
111     {
112         // Option currently returns no systems.  TBD
113         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
114                                    systemName);
115         return;
116     }
117     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
118     {
119         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
120                                    systemName);
121         return;
122     }
123     BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
124 
125     // Make call to post-code service to request clear all
126     crow::connections::systemBus->async_method_call(
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     crow::connections::systemBus->async_method_call(
345         [asyncResp, entryId, bootIndex,
346          codeIndex](const boost::system::error_code& ec,
347                     const boost::container::flat_map<
348                         uint64_t, std::tuple<std::vector<uint8_t>,
349                                              std::vector<uint8_t>>>& postcode) {
350             if (ec)
351             {
352                 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
353                 messages::internalError(asyncResp->res);
354                 return;
355             }
356 
357             if (postcode.empty())
358             {
359                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
360                 return;
361             }
362 
363             if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
364             {
365                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
366                 return;
367             }
368         },
369         "xyz.openbmc_project.State.Boot.PostCode0",
370         "/xyz/openbmc_project/State/Boot/PostCode0",
371         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
372         bootIndex);
373 }
374 
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)375 inline void getPostCodeForBoot(
376     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
377     const uint16_t bootIndex, const uint16_t bootCount,
378     const uint64_t entryCount, size_t skip, size_t top)
379 {
380     crow::connections::systemBus->async_method_call(
381         [asyncResp, bootIndex, bootCount, entryCount, skip,
382          top](const boost::system::error_code& ec,
383               const boost::container::flat_map<
384                   uint64_t, std::tuple<std::vector<uint8_t>,
385                                        std::vector<uint8_t>>>& postcode) {
386             if (ec)
387             {
388                 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
389                 messages::internalError(asyncResp->res);
390                 return;
391             }
392 
393             uint64_t endCount = entryCount;
394             if (!postcode.empty())
395             {
396                 endCount = entryCount + postcode.size();
397                 if (skip < endCount && (top + skip) > entryCount)
398                 {
399                     uint64_t thisBootSkip =
400                         std::max(static_cast<uint64_t>(skip), entryCount) -
401                         entryCount;
402                     uint64_t thisBootTop =
403                         std::min(static_cast<uint64_t>(top + skip), endCount) -
404                         entryCount;
405 
406                     fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
407                                       thisBootSkip, thisBootTop);
408                 }
409                 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
410             }
411 
412             // continue to previous bootIndex
413             if (bootIndex < bootCount)
414             {
415                 getPostCodeForBoot(asyncResp,
416                                    static_cast<uint16_t>(bootIndex + 1),
417                                    bootCount, endCount, skip, top);
418             }
419             else if (skip + top < endCount)
420             {
421                 asyncResp->res.jsonValue["Members@odata.nextLink"] =
422                     std::format(
423                         "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
424                         BMCWEB_REDFISH_SYSTEM_URI_NAME) +
425                     std::to_string(skip + top);
426             }
427         },
428         "xyz.openbmc_project.State.Boot.PostCode0",
429         "/xyz/openbmc_project/State/Boot/PostCode0",
430         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
431         bootIndex);
432 }
433 
getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,size_t skip,size_t top)434 inline void getCurrentBootNumber(
435     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, size_t skip,
436     size_t top)
437 {
438     uint64_t entryCount = 0;
439     dbus::utility::getProperty<uint16_t>(
440         "xyz.openbmc_project.State.Boot.PostCode0",
441         "/xyz/openbmc_project/State/Boot/PostCode0",
442         "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
443         [asyncResp, entryCount, skip,
444          top](const boost::system::error_code& ec, const uint16_t bootCount) {
445             if (ec)
446             {
447                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
448                 messages::internalError(asyncResp->res);
449                 return;
450             }
451             getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
452         });
453 }
454 
handleSystemsLogServicesPostCodesEntriesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)455 inline void handleSystemsLogServicesPostCodesEntriesGet(
456     App& app, const crow::Request& req,
457     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
458     const std::string& systemName)
459 {
460     query_param::QueryCapabilities capabilities = {
461         .canDelegateTop = true,
462         .canDelegateSkip = true,
463     };
464     query_param::Query delegatedQuery;
465     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
466                                                   delegatedQuery, capabilities))
467     {
468         return;
469     }
470     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
471     {
472         // Option currently returns no systems.  TBD
473         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
474                                    systemName);
475         return;
476     }
477 
478     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
479     {
480         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
481                                    systemName);
482         return;
483     }
484     asyncResp->res.jsonValue["@odata.type"] =
485         "#LogEntryCollection.LogEntryCollection";
486     asyncResp->res.jsonValue["@odata.id"] =
487         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
488                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
489     asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
490     asyncResp->res.jsonValue["Description"] =
491         "Collection of POST Code Log Entries";
492     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
493     asyncResp->res.jsonValue["Members@odata.count"] = 0;
494     size_t skip = delegatedQuery.skip.value_or(0);
495     size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
496     getCurrentBootNumber(asyncResp, skip, top);
497 }
498 
handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & postCodeID)499 inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(
500     App& app, const crow::Request& req,
501     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
502     const std::string& systemName, const std::string& postCodeID)
503 {
504     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
505     {
506         return;
507     }
508     if (!http_helpers::isContentTypeAllowed(
509             req.getHeaderValue("Accept"),
510             http_helpers::ContentType::OctetStream, true))
511     {
512         asyncResp->res.result(boost::beast::http::status::bad_request);
513         return;
514     }
515     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
516     {
517         // Option currently returns no systems.  TBD
518         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
519                                    systemName);
520         return;
521     }
522     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
523     {
524         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
525                                    systemName);
526         return;
527     }
528 
529     uint64_t currentValue = 0;
530     uint16_t index = 0;
531     if (!parsePostCode(postCodeID, currentValue, index))
532     {
533         messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
534         return;
535     }
536 
537     crow::connections::systemBus->async_method_call(
538         [asyncResp, postCodeID, currentValue](
539             const boost::system::error_code& ec,
540             const std::vector<std::tuple<std::vector<uint8_t>,
541                                          std::vector<uint8_t>>>& postcodes) {
542             if (ec.value() == EBADR)
543             {
544                 messages::resourceNotFound(asyncResp->res, "LogEntry",
545                                            postCodeID);
546                 return;
547             }
548             if (ec)
549             {
550                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
551                 messages::internalError(asyncResp->res);
552                 return;
553             }
554 
555             size_t value = static_cast<size_t>(currentValue) - 1;
556             if (value == std::string::npos || postcodes.size() < currentValue)
557             {
558                 BMCWEB_LOG_WARNING("Wrong currentValue value");
559                 messages::resourceNotFound(asyncResp->res, "LogEntry",
560                                            postCodeID);
561                 return;
562             }
563 
564             const auto& [tID, c] = postcodes[value];
565             if (c.empty())
566             {
567                 BMCWEB_LOG_WARNING("No found post code data");
568                 messages::resourceNotFound(asyncResp->res, "LogEntry",
569                                            postCodeID);
570                 return;
571             }
572             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
573             const char* d = reinterpret_cast<const char*>(c.data());
574             std::string_view strData(d, c.size());
575 
576             asyncResp->res.addHeader(boost::beast::http::field::content_type,
577                                      "application/octet-stream");
578             asyncResp->res.addHeader(
579                 boost::beast::http::field::content_transfer_encoding, "Base64");
580             asyncResp->res.write(crow::utility::base64encode(strData));
581         },
582         "xyz.openbmc_project.State.Boot.PostCode0",
583         "/xyz/openbmc_project/State/Boot/PostCode0",
584         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
585 }
586 
handleSystemsLogServicesPostCodesEntriesEntryGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & targetID)587 inline void handleSystemsLogServicesPostCodesEntriesEntryGet(
588     App& app, const crow::Request& req,
589     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
590     const std::string& systemName, const std::string& targetID)
591 {
592     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
593     {
594         return;
595     }
596     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
597     {
598         // Option currently returns no systems.  TBD
599         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
600                                    systemName);
601         return;
602     }
603     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
604     {
605         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
606                                    systemName);
607         return;
608     }
609 
610     getPostCodeForEntry(asyncResp, targetID);
611 }
612 
requestRoutesSystemsLogServicesPostCode(App & app)613 inline void requestRoutesSystemsLogServicesPostCode(App& app)
614 {
615     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
616         .privileges(redfish::privileges::getLogService)
617         .methods(boost::beast::http::verb::get)(std::bind_front(
618             handleSystemsLogServicesPostCodesGet, std::ref(app)));
619 
620     BMCWEB_ROUTE(
621         app,
622         "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
623         // The following privilege is correct; we need "SubordinateOverrides"
624         // before we can automate it.
625         .privileges({{"ConfigureComponents"}})
626         .methods(boost::beast::http::verb::post)(std::bind_front(
627             handleSystemsLogServicesPostCodesPost, std::ref(app)));
628 
629     BMCWEB_ROUTE(app,
630                  "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
631         .privileges(redfish::privileges::getLogEntryCollection)
632         .methods(boost::beast::http::verb::get)(std::bind_front(
633             handleSystemsLogServicesPostCodesEntriesGet, std::ref(app)));
634 
635     BMCWEB_ROUTE(
636         app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
637         .privileges(redfish::privileges::getLogEntry)
638         .methods(boost::beast::http::verb::get)(std::bind_front(
639             handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app)));
640 
641     BMCWEB_ROUTE(
642         app,
643         "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
644         .privileges(redfish::privileges::getLogEntry)
645         .methods(boost::beast::http::verb::get)(std::bind_front(
646             handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet,
647             std::ref(app)));
648 }
649 } // namespace redfish
650