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