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