blob: 3788e550c5bfdfa6894edab458eb2e3ccf114147 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2020 Intel Corporation
James Feist46229572020-02-19 15:11:58 -08004#pragma once
5
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08006#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08007#include "async_resp.hpp"
8#include "dbus_singleton.hpp"
9#include "error_messages.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080010#include "event_service_manager.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070011#include "generated/enums/resource.hpp"
12#include "generated/enums/task_service.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010013#include "http/parsing.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080014#include "http_request.hpp"
15#include "http_response.hpp"
16#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080017#include "query.hpp"
18#include "registries/privilege_registry.hpp"
19#include "task_messages.hpp"
Corey Ethington08fad5d2025-07-31 12:14:27 -040020#include "utils/etag_utils.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080021#include "utils/time_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022
Ed Tanousd7857202025-01-28 15:32:26 -080023#include <boost/asio/error.hpp>
Ed Tanousd43cd0c2020-09-30 20:46:53 -070024#include <boost/asio/post.hpp>
25#include <boost/asio/steady_timer.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080026#include <boost/beast/http/field.hpp>
27#include <boost/beast/http/status.hpp>
28#include <boost/beast/http/verb.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070029#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080030#include <boost/url/url.hpp>
31#include <nlohmann/json.hpp>
32#include <sdbusplus/bus.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080033#include <sdbusplus/bus/match.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080034#include <sdbusplus/message.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035
Ed Tanousd7857202025-01-28 15:32:26 -080036#include <algorithm>
37#include <array>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038#include <chrono>
Ed Tanousd7857202025-01-28 15:32:26 -080039#include <cstddef>
40#include <ctime>
41#include <deque>
42#include <functional>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080043#include <memory>
Ed Tanousd7857202025-01-28 15:32:26 -080044#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070045#include <ranges>
Ed Tanousd7857202025-01-28 15:32:26 -080046#include <string>
47#include <string_view>
48#include <utility>
James Feist46229572020-02-19 15:11:58 -080049
50namespace redfish
51{
52
53namespace task
54{
55constexpr size_t maxTaskCount = 100; // arbitrary limit
56
Ed Tanouscf9e4172022-12-21 09:30:16 -080057// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
James Feist46229572020-02-19 15:11:58 -080058static std::deque<std::shared_ptr<struct TaskData>> tasks;
59
James Feist32898ce2020-03-10 16:16:52 -070060constexpr bool completed = true;
61
James Feistfe306722020-03-12 16:32:08 -070062struct Payload
63{
Ed Tanous4e23a442022-06-06 09:57:26 -070064 explicit Payload(const crow::Request& req) :
Ed Tanous39662a32023-02-06 15:09:46 -080065 targetUri(req.url().encoded_path()), httpOperation(req.methodString()),
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010066 httpHeaders(nlohmann::json::array())
James Feistfe306722020-03-12 16:32:08 -070067 {
68 using field_ns = boost::beast::http::field;
69 constexpr const std::array<boost::beast::http::field, 7>
70 headerWhitelist = {field_ns::accept, field_ns::accept_encoding,
71 field_ns::user_agent, field_ns::host,
72 field_ns::connection, field_ns::content_length,
73 field_ns::upgrade};
74
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010075 JsonParseResult ret = parseRequestAsJson(req, jsonBody);
76 if (ret != JsonParseResult::Success)
James Feistfe306722020-03-12 16:32:08 -070077 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010078 return;
James Feistfe306722020-03-12 16:32:08 -070079 }
80
Ed Tanous98fe7402023-02-14 14:50:33 -080081 for (const auto& field : req.fields())
James Feistfe306722020-03-12 16:32:08 -070082 {
Ed Tanous3544d2a2023-08-06 18:12:20 -070083 if (std::ranges::find(headerWhitelist, field.name()) ==
84 headerWhitelist.end())
James Feistfe306722020-03-12 16:32:08 -070085 {
86 continue;
87 }
88 std::string header;
Patrick Williamsbd79bce2024-08-16 15:22:20 -040089 header.reserve(
90 field.name_string().size() + 2 + field.value().size());
James Feistfe306722020-03-12 16:32:08 -070091 header += field.name_string();
92 header += ": ";
93 header += field.value();
94 httpHeaders.emplace_back(std::move(header));
95 }
96 }
97 Payload() = delete;
98
99 std::string targetUri;
100 std::string httpOperation;
101 nlohmann::json httpHeaders;
102 nlohmann::json jsonBody;
103};
104
James Feist46229572020-02-19 15:11:58 -0800105struct TaskData : std::enable_shared_from_this<TaskData>
106{
107 private:
Patrick Williams59d494e2022-07-22 19:26:55 -0500108 TaskData(
109 std::function<bool(boost::system::error_code, sdbusplus::message_t&,
110 const std::shared_ptr<TaskData>&)>&& handler,
111 const std::string& matchIn, size_t idx) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400112 callback(std::move(handler)), matchStr(matchIn), index(idx),
James Feist46229572020-02-19 15:11:58 -0800113 startTime(std::chrono::system_clock::to_time_t(
114 std::chrono::system_clock::now())),
115 status("OK"), state("Running"), messages(nlohmann::json::array()),
116 timer(crow::connections::systemBus->get_io_context())
117
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500118 {}
James Feist46229572020-02-19 15:11:58 -0800119
120 public:
Ed Tanousd609fd62020-09-28 19:08:03 -0700121 TaskData() = delete;
122
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500123 static std::shared_ptr<TaskData>& createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -0500124 std::function<bool(boost::system::error_code, sdbusplus::message_t&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500125 const std::shared_ptr<TaskData>&)>&& handler,
126 const std::string& match)
James Feist46229572020-02-19 15:11:58 -0800127 {
128 static size_t lastTask = 0;
129 struct MakeSharedHelper : public TaskData
130 {
131 MakeSharedHelper(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500132 std::function<bool(boost::system::error_code,
Patrick Williams59d494e2022-07-22 19:26:55 -0500133 sdbusplus::message_t&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500134 const std::shared_ptr<TaskData>&)>&& handler,
Ed Tanous23a21a12020-07-25 04:45:05 +0000135 const std::string& match2, size_t idx) :
136 TaskData(std::move(handler), match2, idx)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500137 {}
James Feist46229572020-02-19 15:11:58 -0800138 };
139
140 if (tasks.size() >= maxTaskCount)
141 {
Rohit PAI9f038942025-03-10 15:29:56 +0530142 const auto last = getTaskToRemove();
James Feist46229572020-02-19 15:11:58 -0800143
144 // destroy all references
Rohit PAI9f038942025-03-10 15:29:56 +0530145 (*last)->timer.cancel();
146 (*last)->match.reset();
147 tasks.erase(last);
James Feist46229572020-02-19 15:11:58 -0800148 }
149
150 return tasks.emplace_back(std::make_shared<MakeSharedHelper>(
151 std::move(handler), match, lastTask++));
152 }
153
Rohit PAI9f038942025-03-10 15:29:56 +0530154 /**
155 * @brief Get the first completed/aborted task or oldest running task to
156 * remove
157 */
158 static std::deque<std::shared_ptr<TaskData>>::iterator getTaskToRemove()
159 {
160 static constexpr std::array<std::string_view, 5> activeStates = {
161 "Running", "Pending", "Starting", "Suspended", "Interrupted"};
162
163 auto it =
164 std::find_if(tasks.begin(), tasks.end(), [](const auto& task) {
165 return std::ranges::find(activeStates, task->state) ==
166 activeStates.end();
167 });
168
169 return (it != tasks.end()) ? it : tasks.begin();
170 }
171
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500172 void populateResp(crow::Response& res, size_t retryAfterSeconds = 30)
James Feist46229572020-02-19 15:11:58 -0800173 {
174 if (!endTime)
175 {
176 res.result(boost::beast::http::status::accepted);
177 std::string strIdx = std::to_string(index);
Ed Tanousfdbce792024-06-26 14:48:46 -0700178 boost::urls::url uri =
179 boost::urls::format("/redfish/v1/TaskService/Tasks/{}", strIdx);
Ed Tanous14766872022-03-15 10:44:42 -0700180
181 res.jsonValue["@odata.id"] = uri;
182 res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task";
183 res.jsonValue["Id"] = strIdx;
184 res.jsonValue["TaskState"] = state;
185 res.jsonValue["TaskStatus"] = status;
186
Ed Tanousfdbce792024-06-26 14:48:46 -0700187 boost::urls::url taskMonitor = boost::urls::format(
188 "/redfish/v1/TaskService/TaskMonitors/{}", strIdx);
189
James Feist46229572020-02-19 15:11:58 -0800190 res.addHeader(boost::beast::http::field::location,
Ed Tanousfdbce792024-06-26 14:48:46 -0700191 taskMonitor.buffer());
James Feist46229572020-02-19 15:11:58 -0800192 res.addHeader(boost::beast::http::field::retry_after,
193 std::to_string(retryAfterSeconds));
Chinmay Shripad Hegde29e2bdd2025-06-06 16:23:47 +0530194 res.jsonValue["Name"] = "Task " + strIdx;
195 res.jsonValue["StartTime"] =
196 redfish::time_utils::getDateTimeStdtime(startTime);
197 res.jsonValue["Messages"] = messages;
198 res.jsonValue["TaskMonitor"] = taskMonitor;
199 res.jsonValue["HidePayload"] = !payload;
200 if (payload)
201 {
202 const task::Payload& p = *payload;
203 nlohmann::json::object_t payloadObj;
204 payloadObj["TargetUri"] = p.targetUri;
205 payloadObj["HttpOperation"] = p.httpOperation;
206 payloadObj["HttpHeaders"] = p.httpHeaders;
207 if (p.jsonBody.is_object())
208 {
209 payloadObj["JsonBody"] = p.jsonBody.dump(
210 2, ' ', true, nlohmann::json::error_handler_t::replace);
211 }
212 res.jsonValue["Payload"] = std::move(payloadObj);
213 }
214 res.jsonValue["PercentComplete"] = percentComplete;
James Feist46229572020-02-19 15:11:58 -0800215 }
216 else if (!gave204)
217 {
218 res.result(boost::beast::http::status::no_content);
219 gave204 = true;
220 }
221 }
222
Ed Tanousd609fd62020-09-28 19:08:03 -0700223 void finishTask()
James Feist46229572020-02-19 15:11:58 -0800224 {
225 endTime = std::chrono::system_clock::to_time_t(
226 std::chrono::system_clock::now());
227 }
228
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229 void extendTimer(const std::chrono::seconds& timeout)
James Feist46229572020-02-19 15:11:58 -0800230 {
James Feist46229572020-02-19 15:11:58 -0800231 timer.expires_after(timeout);
232 timer.async_wait(
233 [self = shared_from_this()](boost::system::error_code ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400234 if (ec == boost::asio::error::operation_aborted)
235 {
236 return; // completed successfully
237 }
238 if (!ec)
239 {
240 // change ec to error as timer expired
241 ec = boost::asio::error::operation_aborted;
242 }
243 self->match.reset();
244 sdbusplus::message_t msg;
245 self->finishTask();
246 self->state = "Cancelled";
247 self->status = "Warning";
248 self->messages.emplace_back(
249 messages::taskAborted(std::to_string(self->index)));
250 // Send event :TaskAborted
Ed Tanousdaadfb22024-12-20 09:25:54 -0800251 sendTaskEvent(self->state, self->index);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400252 self->callback(ec, msg, self);
253 });
James Feistfd9ab9e2020-05-19 13:48:07 -0700254 }
255
Ed Tanous26ccae32023-02-16 10:28:44 -0800256 static void sendTaskEvent(std::string_view state, size_t index)
Sunitha Harishe7686572020-07-15 02:32:44 -0500257 {
Sunitha Harishe7686572020-07-15 02:32:44 -0500258 // TaskState enums which should send out an event are:
259 // "Starting" = taskResumed
260 // "Running" = taskStarted
261 // "Suspended" = taskPaused
262 // "Interrupted" = taskPaused
263 // "Pending" = taskPaused
264 // "Stopping" = taskAborted
265 // "Completed" = taskCompletedOK
266 // "Killed" = taskRemoved
267 // "Exception" = taskCompletedWarning
268 // "Cancelled" = taskCancelled
Ed Tanous82b286f2025-05-06 13:29:48 -0700269 nlohmann::json::object_t event;
Ed Tanousf8fe2212024-06-16 14:51:23 -0700270 std::string indexStr = std::to_string(index);
Sunitha Harishe7686572020-07-15 02:32:44 -0500271 if (state == "Starting")
272 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700273 event = redfish::messages::taskResumed(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500274 }
275 else if (state == "Running")
276 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700277 event = redfish::messages::taskStarted(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500278 }
279 else if ((state == "Suspended") || (state == "Interrupted") ||
280 (state == "Pending"))
281 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700282 event = redfish::messages::taskPaused(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500283 }
284 else if (state == "Stopping")
285 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700286 event = redfish::messages::taskAborted(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500287 }
288 else if (state == "Completed")
289 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700290 event = redfish::messages::taskCompletedOK(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500291 }
292 else if (state == "Killed")
293 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700294 event = redfish::messages::taskRemoved(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500295 }
296 else if (state == "Exception")
297 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700298 event = redfish::messages::taskCompletedWarning(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500299 }
300 else if (state == "Cancelled")
301 {
Ed Tanousf8fe2212024-06-16 14:51:23 -0700302 event = redfish::messages::taskCancelled(indexStr);
Sunitha Harishe7686572020-07-15 02:32:44 -0500303 }
304 else
305 {
Ed Tanous62598e32023-07-17 17:06:25 -0700306 BMCWEB_LOG_INFO("sendTaskEvent: No events to send");
Ed Tanousf8fe2212024-06-16 14:51:23 -0700307 return;
Sunitha Harishe7686572020-07-15 02:32:44 -0500308 }
Ed Tanousf8fe2212024-06-16 14:51:23 -0700309 boost::urls::url origin =
310 boost::urls::format("/redfish/v1/TaskService/Tasks/{}", index);
311 EventServiceManager::getInstance().sendEvent(event, origin.buffer(),
312 "Task");
Sunitha Harishe7686572020-07-15 02:32:44 -0500313 }
314
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500315 void startTimer(const std::chrono::seconds& timeout)
James Feistfd9ab9e2020-05-19 13:48:07 -0700316 {
317 if (match)
318 {
319 return;
320 }
Patrick Williams59d494e2022-07-22 19:26:55 -0500321 match = std::make_unique<sdbusplus::bus::match_t>(
322 static_cast<sdbusplus::bus_t&>(*crow::connections::systemBus),
James Feistfd9ab9e2020-05-19 13:48:07 -0700323 matchStr,
Patrick Williams59d494e2022-07-22 19:26:55 -0500324 [self = shared_from_this()](sdbusplus::message_t& message) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400325 boost::system::error_code ec;
James Feistfd9ab9e2020-05-19 13:48:07 -0700326
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400327 // callback to return True if callback is done, callback needs
328 // to update status itself if needed
329 if (self->callback(ec, message, self) == task::completed)
330 {
331 self->timer.cancel();
332 self->finishTask();
James Feistfd9ab9e2020-05-19 13:48:07 -0700333
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400334 // Send event
Ed Tanousdaadfb22024-12-20 09:25:54 -0800335 sendTaskEvent(self->state, self->index);
Sunitha Harishe7686572020-07-15 02:32:44 -0500336
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400337 // reset the match after the callback was successful
338 boost::asio::post(
339 crow::connections::systemBus->get_io_context(),
340 [self] { self->match.reset(); });
341 return;
342 }
343 });
James Feistfd9ab9e2020-05-19 13:48:07 -0700344
345 extendTimer(timeout);
James Feiste5d50062020-05-11 17:29:00 -0700346 messages.emplace_back(messages::taskStarted(std::to_string(index)));
Sunitha Harishe7686572020-07-15 02:32:44 -0500347 // Send event : TaskStarted
348 sendTaskEvent(state, index);
James Feist46229572020-02-19 15:11:58 -0800349 }
350
Patrick Williams59d494e2022-07-22 19:26:55 -0500351 std::function<bool(boost::system::error_code, sdbusplus::message_t&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500352 const std::shared_ptr<TaskData>&)>
James Feist46229572020-02-19 15:11:58 -0800353 callback;
354 std::string matchStr;
355 size_t index;
356 time_t startTime;
357 std::string status;
358 std::string state;
359 nlohmann::json messages;
360 boost::asio::steady_timer timer;
Patrick Williams59d494e2022-07-22 19:26:55 -0500361 std::unique_ptr<sdbusplus::bus::match_t> match;
James Feist46229572020-02-19 15:11:58 -0800362 std::optional<time_t> endTime;
James Feistfe306722020-03-12 16:32:08 -0700363 std::optional<Payload> payload;
James Feist46229572020-02-19 15:11:58 -0800364 bool gave204 = false;
George Liu6868ff52021-01-02 11:37:41 +0800365 int percentComplete = 0;
James Feist46229572020-02-19 15:11:58 -0800366};
367
368} // namespace task
369
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700370inline void requestRoutesTaskMonitor(App& app)
James Feist46229572020-02-19 15:11:58 -0800371{
Ed Tanousfdbce792024-06-26 14:48:46 -0700372 BMCWEB_ROUTE(app, "/redfish/v1/TaskService/TaskMonitors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700373 .privileges(redfish::privileges::getTask)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700374 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700375 [&app](const crow::Request& req,
376 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
377 const std::string& strParam) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400378 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
379 {
380 return;
381 }
382 auto find = std::ranges::find_if(
383 task::tasks,
384 [&strParam](const std::shared_ptr<task::TaskData>& task) {
385 if (!task)
386 {
387 return false;
388 }
James Feist46229572020-02-19 15:11:58 -0800389
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400390 // we compare against the string version as on failure
391 // strtoul returns 0
392 return std::to_string(task->index) == strParam;
393 });
Ed Tanous002d39b2022-05-31 08:59:27 -0700394
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400395 if (find == task::tasks.end())
396 {
397 messages::resourceNotFound(asyncResp->res, "Task",
398 strParam);
399 return;
400 }
401 std::shared_ptr<task::TaskData>& ptr = *find;
402 // monitor expires after 204
403 if (ptr->gave204)
404 {
405 messages::resourceNotFound(asyncResp->res, "Task",
406 strParam);
407 return;
408 }
409 ptr->populateResp(asyncResp->res);
410 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700411}
412
413inline void requestRoutesTask(App& app)
414{
415 BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700416 .privileges(redfish::privileges::getTask)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700417 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700418 [&app](const crow::Request& req,
419 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
420 const std::string& strParam) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400421 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
422 {
423 return;
424 }
425 auto find = std::ranges::find_if(
426 task::tasks,
427 [&strParam](const std::shared_ptr<task::TaskData>& task) {
428 if (!task)
429 {
430 return false;
431 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700432
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400433 // we compare against the string version as on failure
434 // strtoul returns 0
435 return std::to_string(task->index) == strParam;
436 });
Ed Tanous002d39b2022-05-31 08:59:27 -0700437
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400438 if (find == task::tasks.end())
439 {
440 messages::resourceNotFound(asyncResp->res, "Task",
441 strParam);
442 return;
443 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700444
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400445 const std::shared_ptr<task::TaskData>& ptr = *find;
Ed Tanous002d39b2022-05-31 08:59:27 -0700446
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400447 asyncResp->res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task";
448 asyncResp->res.jsonValue["Id"] = strParam;
449 asyncResp->res.jsonValue["Name"] = "Task " + strParam;
450 asyncResp->res.jsonValue["TaskState"] = ptr->state;
451 asyncResp->res.jsonValue["StartTime"] =
452 redfish::time_utils::getDateTimeStdtime(ptr->startTime);
453 if (ptr->endTime)
454 {
455 asyncResp->res.jsonValue["EndTime"] =
456 redfish::time_utils::getDateTimeStdtime(
457 *(ptr->endTime));
458 }
459 asyncResp->res.jsonValue["TaskStatus"] = ptr->status;
460 asyncResp->res.jsonValue["Messages"] = ptr->messages;
461 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
462 "/redfish/v1/TaskService/Tasks/{}", strParam);
463 if (!ptr->gave204)
464 {
465 asyncResp->res.jsonValue["TaskMonitor"] =
466 boost::urls::format(
467 "/redfish/v1/TaskService/TaskMonitors/{}",
468 strParam);
469 }
Arun Thomas Baby5db7dfd2023-05-02 03:22:23 -0700470
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400471 asyncResp->res.jsonValue["HidePayload"] = !ptr->payload;
Arun Thomas Baby5db7dfd2023-05-02 03:22:23 -0700472
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400473 if (ptr->payload)
474 {
475 const task::Payload& p = *(ptr->payload);
476 asyncResp->res.jsonValue["Payload"]["TargetUri"] =
477 p.targetUri;
478 asyncResp->res.jsonValue["Payload"]["HttpOperation"] =
479 p.httpOperation;
480 asyncResp->res.jsonValue["Payload"]["HttpHeaders"] =
481 p.httpHeaders;
482 asyncResp->res.jsonValue["Payload"]["JsonBody"] =
483 p.jsonBody.dump(
484 -1, ' ', true,
485 nlohmann::json::error_handler_t::replace);
486 }
487 asyncResp->res.jsonValue["PercentComplete"] =
488 ptr->percentComplete;
489 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700490}
James Feist46229572020-02-19 15:11:58 -0800491
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700492inline void requestRoutesTaskCollection(App& app)
James Feist46229572020-02-19 15:11:58 -0800493{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700494 BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/")
Ed Tanoused398212021-06-09 17:05:54 -0700495 .privileges(redfish::privileges::getTaskCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700496 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700497 [&app](const crow::Request& req,
498 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400499 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
500 {
501 return;
502 }
503 asyncResp->res.jsonValue["@odata.type"] =
504 "#TaskCollection.TaskCollection";
505 asyncResp->res.jsonValue["@odata.id"] =
506 "/redfish/v1/TaskService/Tasks";
507 asyncResp->res.jsonValue["Name"] = "Task Collection";
508 asyncResp->res.jsonValue["Members@odata.count"] =
509 task::tasks.size();
510 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
511 members = nlohmann::json::array();
James Feist46229572020-02-19 15:11:58 -0800512
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400513 for (const std::shared_ptr<task::TaskData>& task : task::tasks)
514 {
515 if (task == nullptr)
516 {
517 continue; // shouldn't be possible
518 }
519 nlohmann::json::object_t member;
520 member["@odata.id"] =
521 boost::urls::format("/redfish/v1/TaskService/Tasks/{}",
522 std::to_string(task->index));
523 members.emplace_back(std::move(member));
524 }
525 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700526}
zhanghch058d1b46d2021-04-01 11:18:24 +0800527
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700528inline void requestRoutesTaskService(App& app)
James Feist46229572020-02-19 15:11:58 -0800529{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700530 BMCWEB_ROUTE(app, "/redfish/v1/TaskService/")
Ed Tanoused398212021-06-09 17:05:54 -0700531 .privileges(redfish::privileges::getTaskService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700532 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700533 [&app](const crow::Request& req,
534 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400535 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
536 {
537 return;
538 }
539 asyncResp->res.jsonValue["@odata.type"] =
540 "#TaskService.v1_1_4.TaskService";
541 asyncResp->res.jsonValue["@odata.id"] =
542 "/redfish/v1/TaskService";
543 asyncResp->res.jsonValue["Name"] = "Task Service";
544 asyncResp->res.jsonValue["Id"] = "TaskService";
545 asyncResp->res.jsonValue["DateTime"] =
546 redfish::time_utils::getDateTimeOffsetNow().first;
547 asyncResp->res.jsonValue["CompletedTaskOverWritePolicy"] =
548 task_service::OverWritePolicy::Oldest;
James Feist46229572020-02-19 15:11:58 -0800549
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400550 asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] =
551 true;
James Feist46229572020-02-19 15:11:58 -0800552
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400553 asyncResp->res.jsonValue["Status"]["State"] =
554 resource::State::Enabled;
555 asyncResp->res.jsonValue["ServiceEnabled"] = true;
556 asyncResp->res.jsonValue["Tasks"]["@odata.id"] =
557 "/redfish/v1/TaskService/Tasks";
Corey Ethington08fad5d2025-07-31 12:14:27 -0400558
559 etag_utils::setEtagOmitDateTimeHandler(asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400560 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700561}
James Feist46229572020-02-19 15:11:58 -0800562
563} // namespace redfish