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