xref: /openbmc/bmcweb/features/redfish/lib/task.hpp (revision daadfb2e6ee2980f4d3160f7d9252404df5ad6e2)
146229577SJames Feist /*
26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
1546229577SJames Feist */
1646229577SJames Feist #pragma once
1746229577SJames Feist 
183ccb3adbSEd Tanous #include "app.hpp"
193ccb3adbSEd Tanous #include "dbus_utility.hpp"
203ccb3adbSEd Tanous #include "event_service_manager.hpp"
21539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
22539d8c6bSEd Tanous #include "generated/enums/task_service.hpp"
231aa0c2b8SEd Tanous #include "http/parsing.hpp"
243ccb3adbSEd Tanous #include "query.hpp"
253ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
263ccb3adbSEd Tanous #include "task_messages.hpp"
273ccb3adbSEd Tanous 
28d43cd0caSEd Tanous #include <boost/asio/post.hpp>
29d43cd0caSEd Tanous #include <boost/asio/steady_timer.hpp>
30ef4c65b7SEd Tanous #include <boost/url/format.hpp>
313ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
321214b7e7SGunnar Mills 
331214b7e7SGunnar Mills #include <chrono>
343ccb3adbSEd Tanous #include <memory>
353544d2a7SEd Tanous #include <ranges>
3646229577SJames Feist #include <variant>
3746229577SJames Feist 
3846229577SJames Feist namespace redfish
3946229577SJames Feist {
4046229577SJames Feist 
4146229577SJames Feist namespace task
4246229577SJames Feist {
4346229577SJames Feist constexpr size_t maxTaskCount = 100; // arbitrary limit
4446229577SJames Feist 
45cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
4646229577SJames Feist static std::deque<std::shared_ptr<struct TaskData>> tasks;
4746229577SJames Feist 
4832898ceaSJames Feist constexpr bool completed = true;
4932898ceaSJames Feist 
50fe306728SJames Feist struct Payload
51fe306728SJames Feist {
524e23a444SEd Tanous     explicit Payload(const crow::Request& req) :
5339662a3bSEd Tanous         targetUri(req.url().encoded_path()), httpOperation(req.methodString()),
541aa0c2b8SEd Tanous         httpHeaders(nlohmann::json::array())
55fe306728SJames Feist     {
56fe306728SJames Feist         using field_ns = boost::beast::http::field;
57fe306728SJames Feist         constexpr const std::array<boost::beast::http::field, 7>
58fe306728SJames Feist             headerWhitelist = {field_ns::accept,     field_ns::accept_encoding,
59fe306728SJames Feist                                field_ns::user_agent, field_ns::host,
60fe306728SJames Feist                                field_ns::connection, field_ns::content_length,
61fe306728SJames Feist                                field_ns::upgrade};
62fe306728SJames Feist 
631aa0c2b8SEd Tanous         JsonParseResult ret = parseRequestAsJson(req, jsonBody);
641aa0c2b8SEd Tanous         if (ret != JsonParseResult::Success)
65fe306728SJames Feist         {
661aa0c2b8SEd Tanous             return;
67fe306728SJames Feist         }
68fe306728SJames Feist 
6998fe740bSEd Tanous         for (const auto& field : req.fields())
70fe306728SJames Feist         {
713544d2a7SEd Tanous             if (std::ranges::find(headerWhitelist, field.name()) ==
723544d2a7SEd Tanous                 headerWhitelist.end())
73fe306728SJames Feist             {
74fe306728SJames Feist                 continue;
75fe306728SJames Feist             }
76fe306728SJames Feist             std::string header;
77bd79bce8SPatrick Williams             header.reserve(
78bd79bce8SPatrick Williams                 field.name_string().size() + 2 + field.value().size());
79fe306728SJames Feist             header += field.name_string();
80fe306728SJames Feist             header += ": ";
81fe306728SJames Feist             header += field.value();
82fe306728SJames Feist             httpHeaders.emplace_back(std::move(header));
83fe306728SJames Feist         }
84fe306728SJames Feist     }
85fe306728SJames Feist     Payload() = delete;
86fe306728SJames Feist 
87fe306728SJames Feist     std::string targetUri;
88fe306728SJames Feist     std::string httpOperation;
89fe306728SJames Feist     nlohmann::json httpHeaders;
90fe306728SJames Feist     nlohmann::json jsonBody;
91fe306728SJames Feist };
92fe306728SJames Feist 
9346229577SJames Feist struct TaskData : std::enable_shared_from_this<TaskData>
9446229577SJames Feist {
9546229577SJames Feist   private:
9659d494eeSPatrick Williams     TaskData(
9759d494eeSPatrick Williams         std::function<bool(boost::system::error_code, sdbusplus::message_t&,
9846229577SJames Feist                            const std::shared_ptr<TaskData>&)>&& handler,
9923a21a1cSEd Tanous         const std::string& matchIn, size_t idx) :
100bd79bce8SPatrick Williams         callback(std::move(handler)), matchStr(matchIn), index(idx),
10146229577SJames Feist         startTime(std::chrono::system_clock::to_time_t(
10246229577SJames Feist             std::chrono::system_clock::now())),
10346229577SJames Feist         status("OK"), state("Running"), messages(nlohmann::json::array()),
10446229577SJames Feist         timer(crow::connections::systemBus->get_io_context())
10546229577SJames Feist 
1061214b7e7SGunnar Mills     {}
10746229577SJames Feist 
10846229577SJames Feist   public:
109d609fd6eSEd Tanous     TaskData() = delete;
110d609fd6eSEd Tanous 
11146229577SJames Feist     static std::shared_ptr<TaskData>& createTask(
11259d494eeSPatrick Williams         std::function<bool(boost::system::error_code, sdbusplus::message_t&,
11346229577SJames Feist                            const std::shared_ptr<TaskData>&)>&& handler,
11446229577SJames Feist         const std::string& match)
11546229577SJames Feist     {
11646229577SJames Feist         static size_t lastTask = 0;
11746229577SJames Feist         struct MakeSharedHelper : public TaskData
11846229577SJames Feist         {
11946229577SJames Feist             MakeSharedHelper(
1201214b7e7SGunnar Mills                 std::function<bool(boost::system::error_code,
12159d494eeSPatrick Williams                                    sdbusplus::message_t&,
12246229577SJames Feist                                    const std::shared_ptr<TaskData>&)>&& handler,
12323a21a1cSEd Tanous                 const std::string& match2, size_t idx) :
12423a21a1cSEd Tanous                 TaskData(std::move(handler), match2, idx)
1251214b7e7SGunnar Mills             {}
12646229577SJames Feist         };
12746229577SJames Feist 
12846229577SJames Feist         if (tasks.size() >= maxTaskCount)
12946229577SJames Feist         {
13002cad96eSEd Tanous             const auto& last = tasks.front();
13146229577SJames Feist 
13246229577SJames Feist             // destroy all references
13346229577SJames Feist             last->timer.cancel();
13446229577SJames Feist             last->match.reset();
13546229577SJames Feist             tasks.pop_front();
13646229577SJames Feist         }
13746229577SJames Feist 
13846229577SJames Feist         return tasks.emplace_back(std::make_shared<MakeSharedHelper>(
13946229577SJames Feist             std::move(handler), match, lastTask++));
14046229577SJames Feist     }
14146229577SJames Feist 
14246229577SJames Feist     void populateResp(crow::Response& res, size_t retryAfterSeconds = 30)
14346229577SJames Feist     {
14446229577SJames Feist         if (!endTime)
14546229577SJames Feist         {
14646229577SJames Feist             res.result(boost::beast::http::status::accepted);
14746229577SJames Feist             std::string strIdx = std::to_string(index);
148fdbce79bSEd Tanous             boost::urls::url uri =
149fdbce79bSEd Tanous                 boost::urls::format("/redfish/v1/TaskService/Tasks/{}", strIdx);
1501476687dSEd Tanous 
1511476687dSEd Tanous             res.jsonValue["@odata.id"] = uri;
1521476687dSEd Tanous             res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task";
1531476687dSEd Tanous             res.jsonValue["Id"] = strIdx;
1541476687dSEd Tanous             res.jsonValue["TaskState"] = state;
1551476687dSEd Tanous             res.jsonValue["TaskStatus"] = status;
1561476687dSEd Tanous 
157fdbce79bSEd Tanous             boost::urls::url taskMonitor = boost::urls::format(
158fdbce79bSEd Tanous                 "/redfish/v1/TaskService/TaskMonitors/{}", strIdx);
159fdbce79bSEd Tanous 
16046229577SJames Feist             res.addHeader(boost::beast::http::field::location,
161fdbce79bSEd Tanous                           taskMonitor.buffer());
16246229577SJames Feist             res.addHeader(boost::beast::http::field::retry_after,
16346229577SJames Feist                           std::to_string(retryAfterSeconds));
16446229577SJames Feist         }
16546229577SJames Feist         else if (!gave204)
16646229577SJames Feist         {
16746229577SJames Feist             res.result(boost::beast::http::status::no_content);
16846229577SJames Feist             gave204 = true;
16946229577SJames Feist         }
17046229577SJames Feist     }
17146229577SJames Feist 
172d609fd6eSEd Tanous     void finishTask()
17346229577SJames Feist     {
17446229577SJames Feist         endTime = std::chrono::system_clock::to_time_t(
17546229577SJames Feist             std::chrono::system_clock::now());
17646229577SJames Feist     }
17746229577SJames Feist 
178fd9ab9e1SJames Feist     void extendTimer(const std::chrono::seconds& timeout)
17946229577SJames Feist     {
18046229577SJames Feist         timer.expires_after(timeout);
18146229577SJames Feist         timer.async_wait(
18246229577SJames Feist             [self = shared_from_this()](boost::system::error_code ec) {
18346229577SJames Feist                 if (ec == boost::asio::error::operation_aborted)
18446229577SJames Feist                 {
1854e0453b1SGunnar Mills                     return; // completed successfully
18646229577SJames Feist                 }
18746229577SJames Feist                 if (!ec)
18846229577SJames Feist                 {
18946229577SJames Feist                     // change ec to error as timer expired
19046229577SJames Feist                     ec = boost::asio::error::operation_aborted;
19146229577SJames Feist                 }
19246229577SJames Feist                 self->match.reset();
19359d494eeSPatrick Williams                 sdbusplus::message_t msg;
19446229577SJames Feist                 self->finishTask();
19546229577SJames Feist                 self->state = "Cancelled";
19646229577SJames Feist                 self->status = "Warning";
197e5d5006bSJames Feist                 self->messages.emplace_back(
198e5d5006bSJames Feist                     messages::taskAborted(std::to_string(self->index)));
199e7686576SSunitha Harish                 // Send event :TaskAborted
200*daadfb2eSEd Tanous                 sendTaskEvent(self->state, self->index);
20146229577SJames Feist                 self->callback(ec, msg, self);
20246229577SJames Feist             });
203fd9ab9e1SJames Feist     }
204fd9ab9e1SJames Feist 
20526ccae32SEd Tanous     static void sendTaskEvent(std::string_view state, size_t index)
206e7686576SSunitha Harish     {
207e7686576SSunitha Harish         // TaskState enums which should send out an event are:
208e7686576SSunitha Harish         // "Starting" = taskResumed
209e7686576SSunitha Harish         // "Running" = taskStarted
210e7686576SSunitha Harish         // "Suspended" = taskPaused
211e7686576SSunitha Harish         // "Interrupted" = taskPaused
212e7686576SSunitha Harish         // "Pending" = taskPaused
213e7686576SSunitha Harish         // "Stopping" = taskAborted
214e7686576SSunitha Harish         // "Completed" = taskCompletedOK
215e7686576SSunitha Harish         // "Killed" = taskRemoved
216e7686576SSunitha Harish         // "Exception" = taskCompletedWarning
217e7686576SSunitha Harish         // "Cancelled" = taskCancelled
218f8fe2211SEd Tanous         nlohmann::json event;
219f8fe2211SEd Tanous         std::string indexStr = std::to_string(index);
220e7686576SSunitha Harish         if (state == "Starting")
221e7686576SSunitha Harish         {
222f8fe2211SEd Tanous             event = redfish::messages::taskResumed(indexStr);
223e7686576SSunitha Harish         }
224e7686576SSunitha Harish         else if (state == "Running")
225e7686576SSunitha Harish         {
226f8fe2211SEd Tanous             event = redfish::messages::taskStarted(indexStr);
227e7686576SSunitha Harish         }
228e7686576SSunitha Harish         else if ((state == "Suspended") || (state == "Interrupted") ||
229e7686576SSunitha Harish                  (state == "Pending"))
230e7686576SSunitha Harish         {
231f8fe2211SEd Tanous             event = redfish::messages::taskPaused(indexStr);
232e7686576SSunitha Harish         }
233e7686576SSunitha Harish         else if (state == "Stopping")
234e7686576SSunitha Harish         {
235f8fe2211SEd Tanous             event = redfish::messages::taskAborted(indexStr);
236e7686576SSunitha Harish         }
237e7686576SSunitha Harish         else if (state == "Completed")
238e7686576SSunitha Harish         {
239f8fe2211SEd Tanous             event = redfish::messages::taskCompletedOK(indexStr);
240e7686576SSunitha Harish         }
241e7686576SSunitha Harish         else if (state == "Killed")
242e7686576SSunitha Harish         {
243f8fe2211SEd Tanous             event = redfish::messages::taskRemoved(indexStr);
244e7686576SSunitha Harish         }
245e7686576SSunitha Harish         else if (state == "Exception")
246e7686576SSunitha Harish         {
247f8fe2211SEd Tanous             event = redfish::messages::taskCompletedWarning(indexStr);
248e7686576SSunitha Harish         }
249e7686576SSunitha Harish         else if (state == "Cancelled")
250e7686576SSunitha Harish         {
251f8fe2211SEd Tanous             event = redfish::messages::taskCancelled(indexStr);
252e7686576SSunitha Harish         }
253e7686576SSunitha Harish         else
254e7686576SSunitha Harish         {
25562598e31SEd Tanous             BMCWEB_LOG_INFO("sendTaskEvent: No events to send");
256f8fe2211SEd Tanous             return;
257e7686576SSunitha Harish         }
258f8fe2211SEd Tanous         boost::urls::url origin =
259f8fe2211SEd Tanous             boost::urls::format("/redfish/v1/TaskService/Tasks/{}", index);
260f8fe2211SEd Tanous         EventServiceManager::getInstance().sendEvent(event, origin.buffer(),
261f8fe2211SEd Tanous                                                      "Task");
262e7686576SSunitha Harish     }
263e7686576SSunitha Harish 
264fd9ab9e1SJames Feist     void startTimer(const std::chrono::seconds& timeout)
265fd9ab9e1SJames Feist     {
266fd9ab9e1SJames Feist         if (match)
267fd9ab9e1SJames Feist         {
268fd9ab9e1SJames Feist             return;
269fd9ab9e1SJames Feist         }
27059d494eeSPatrick Williams         match = std::make_unique<sdbusplus::bus::match_t>(
27159d494eeSPatrick Williams             static_cast<sdbusplus::bus_t&>(*crow::connections::systemBus),
272fd9ab9e1SJames Feist             matchStr,
27359d494eeSPatrick Williams             [self = shared_from_this()](sdbusplus::message_t& message) {
274fd9ab9e1SJames Feist                 boost::system::error_code ec;
275fd9ab9e1SJames Feist 
276fd9ab9e1SJames Feist                 // callback to return True if callback is done, callback needs
277fd9ab9e1SJames Feist                 // to update status itself if needed
278fd9ab9e1SJames Feist                 if (self->callback(ec, message, self) == task::completed)
279fd9ab9e1SJames Feist                 {
280fd9ab9e1SJames Feist                     self->timer.cancel();
281fd9ab9e1SJames Feist                     self->finishTask();
282fd9ab9e1SJames Feist 
283e7686576SSunitha Harish                     // Send event
284*daadfb2eSEd Tanous                     sendTaskEvent(self->state, self->index);
285e7686576SSunitha Harish 
286fd9ab9e1SJames Feist                     // reset the match after the callback was successful
287fd9ab9e1SJames Feist                     boost::asio::post(
288fd9ab9e1SJames Feist                         crow::connections::systemBus->get_io_context(),
289fd9ab9e1SJames Feist                         [self] { self->match.reset(); });
290fd9ab9e1SJames Feist                     return;
291fd9ab9e1SJames Feist                 }
292fd9ab9e1SJames Feist             });
293fd9ab9e1SJames Feist 
294fd9ab9e1SJames Feist         extendTimer(timeout);
295e5d5006bSJames Feist         messages.emplace_back(messages::taskStarted(std::to_string(index)));
296e7686576SSunitha Harish         // Send event : TaskStarted
297e7686576SSunitha Harish         sendTaskEvent(state, index);
29846229577SJames Feist     }
29946229577SJames Feist 
30059d494eeSPatrick Williams     std::function<bool(boost::system::error_code, sdbusplus::message_t&,
30146229577SJames Feist                        const std::shared_ptr<TaskData>&)>
30246229577SJames Feist         callback;
30346229577SJames Feist     std::string matchStr;
30446229577SJames Feist     size_t index;
30546229577SJames Feist     time_t startTime;
30646229577SJames Feist     std::string status;
30746229577SJames Feist     std::string state;
30846229577SJames Feist     nlohmann::json messages;
30946229577SJames Feist     boost::asio::steady_timer timer;
31059d494eeSPatrick Williams     std::unique_ptr<sdbusplus::bus::match_t> match;
31146229577SJames Feist     std::optional<time_t> endTime;
312fe306728SJames Feist     std::optional<Payload> payload;
31346229577SJames Feist     bool gave204 = false;
3146868ff50SGeorge Liu     int percentComplete = 0;
31546229577SJames Feist };
31646229577SJames Feist 
31746229577SJames Feist } // namespace task
31846229577SJames Feist 
3197e860f15SJohn Edward Broadbent inline void requestRoutesTaskMonitor(App& app)
32046229577SJames Feist {
321fdbce79bSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/TaskService/TaskMonitors/<str>/")
322ed398213SEd Tanous         .privileges(redfish::privileges::getTask)
3237e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
32445ca1b86SEd Tanous             [&app](const crow::Request& req,
3257e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3267e860f15SJohn Edward Broadbent                    const std::string& strParam) {
3273ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
32845ca1b86SEd Tanous                 {
32945ca1b86SEd Tanous                     return;
33045ca1b86SEd Tanous                 }
3313544d2a7SEd Tanous                 auto find = std::ranges::find_if(
3323544d2a7SEd Tanous                     task::tasks,
33346229577SJames Feist                     [&strParam](const std::shared_ptr<task::TaskData>& task) {
33446229577SJames Feist                         if (!task)
33546229577SJames Feist                         {
33646229577SJames Feist                             return false;
33746229577SJames Feist                         }
33846229577SJames Feist 
3397e860f15SJohn Edward Broadbent                         // we compare against the string version as on failure
3407e860f15SJohn Edward Broadbent                         // strtoul returns 0
34146229577SJames Feist                         return std::to_string(task->index) == strParam;
34246229577SJames Feist                     });
34346229577SJames Feist 
34446229577SJames Feist                 if (find == task::tasks.end())
34546229577SJames Feist                 {
346bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Task",
347bd79bce8SPatrick Williams                                                strParam);
34846229577SJames Feist                     return;
34946229577SJames Feist                 }
35046229577SJames Feist                 std::shared_ptr<task::TaskData>& ptr = *find;
35146229577SJames Feist                 // monitor expires after 204
35246229577SJames Feist                 if (ptr->gave204)
35346229577SJames Feist                 {
354bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Task",
355bd79bce8SPatrick Williams                                                strParam);
35646229577SJames Feist                     return;
35746229577SJames Feist                 }
35846229577SJames Feist                 ptr->populateResp(asyncResp->res);
3597e860f15SJohn Edward Broadbent             });
36046229577SJames Feist }
36146229577SJames Feist 
3627e860f15SJohn Edward Broadbent inline void requestRoutesTask(App& app)
36346229577SJames Feist {
3647e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/<str>/")
365ed398213SEd Tanous         .privileges(redfish::privileges::getTask)
3667e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
36745ca1b86SEd Tanous             [&app](const crow::Request& req,
3687e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3697e860f15SJohn Edward Broadbent                    const std::string& strParam) {
3703ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
37145ca1b86SEd Tanous                 {
37245ca1b86SEd Tanous                     return;
37345ca1b86SEd Tanous                 }
3743544d2a7SEd Tanous                 auto find = std::ranges::find_if(
3753544d2a7SEd Tanous                     task::tasks,
37646229577SJames Feist                     [&strParam](const std::shared_ptr<task::TaskData>& task) {
37746229577SJames Feist                         if (!task)
37846229577SJames Feist                         {
37946229577SJames Feist                             return false;
38046229577SJames Feist                         }
38146229577SJames Feist 
3827e860f15SJohn Edward Broadbent                         // we compare against the string version as on failure
3837e860f15SJohn Edward Broadbent                         // strtoul returns 0
38446229577SJames Feist                         return std::to_string(task->index) == strParam;
38546229577SJames Feist                     });
38646229577SJames Feist 
38746229577SJames Feist                 if (find == task::tasks.end())
38846229577SJames Feist                 {
389bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Task",
390bd79bce8SPatrick Williams                                                strParam);
39146229577SJames Feist                     return;
39246229577SJames Feist                 }
39346229577SJames Feist 
39402cad96eSEd Tanous                 const std::shared_ptr<task::TaskData>& ptr = *find;
39546229577SJames Feist 
39646229577SJames Feist                 asyncResp->res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task";
39746229577SJames Feist                 asyncResp->res.jsonValue["Id"] = strParam;
39846229577SJames Feist                 asyncResp->res.jsonValue["Name"] = "Task " + strParam;
39946229577SJames Feist                 asyncResp->res.jsonValue["TaskState"] = ptr->state;
40046229577SJames Feist                 asyncResp->res.jsonValue["StartTime"] =
4012b82937eSEd Tanous                     redfish::time_utils::getDateTimeStdtime(ptr->startTime);
40246229577SJames Feist                 if (ptr->endTime)
40346229577SJames Feist                 {
40446229577SJames Feist                     asyncResp->res.jsonValue["EndTime"] =
405bd79bce8SPatrick Williams                         redfish::time_utils::getDateTimeStdtime(
406bd79bce8SPatrick Williams                             *(ptr->endTime));
40746229577SJames Feist                 }
40846229577SJames Feist                 asyncResp->res.jsonValue["TaskStatus"] = ptr->status;
40946229577SJames Feist                 asyncResp->res.jsonValue["Messages"] = ptr->messages;
410bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
411bd79bce8SPatrick Williams                     "/redfish/v1/TaskService/Tasks/{}", strParam);
41246229577SJames Feist                 if (!ptr->gave204)
41346229577SJames Feist                 {
414bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["TaskMonitor"] =
415bd79bce8SPatrick Williams                         boost::urls::format(
416bd79bce8SPatrick Williams                             "/redfish/v1/TaskService/TaskMonitors/{}",
417bd79bce8SPatrick Williams                             strParam);
41846229577SJames Feist                 }
4195db7dfd6SArun Thomas Baby 
4205db7dfd6SArun Thomas Baby                 asyncResp->res.jsonValue["HidePayload"] = !ptr->payload;
4215db7dfd6SArun Thomas Baby 
422fe306728SJames Feist                 if (ptr->payload)
423fe306728SJames Feist                 {
4245fb91ba4SEd Tanous                     const task::Payload& p = *(ptr->payload);
425bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Payload"]["TargetUri"] =
426bd79bce8SPatrick Williams                         p.targetUri;
4271476687dSEd Tanous                     asyncResp->res.jsonValue["Payload"]["HttpOperation"] =
4281476687dSEd Tanous                         p.httpOperation;
429bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Payload"]["HttpHeaders"] =
430bd79bce8SPatrick Williams                         p.httpHeaders;
431bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Payload"]["JsonBody"] =
432bd79bce8SPatrick Williams                         p.jsonBody.dump(
433bd79bce8SPatrick Williams                             -1, ' ', true,
434bd79bce8SPatrick Williams                             nlohmann::json::error_handler_t::replace);
435fe306728SJames Feist                 }
436bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PercentComplete"] =
437bd79bce8SPatrick Williams                     ptr->percentComplete;
4387e860f15SJohn Edward Broadbent             });
43946229577SJames Feist }
44046229577SJames Feist 
4417e860f15SJohn Edward Broadbent inline void requestRoutesTaskCollection(App& app)
44246229577SJames Feist {
4437e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/")
444ed398213SEd Tanous         .privileges(redfish::privileges::getTaskCollection)
4457e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
44645ca1b86SEd Tanous             [&app](const crow::Request& req,
4477e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
4483ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
44945ca1b86SEd Tanous                 {
45045ca1b86SEd Tanous                     return;
45145ca1b86SEd Tanous                 }
45246229577SJames Feist                 asyncResp->res.jsonValue["@odata.type"] =
45346229577SJames Feist                     "#TaskCollection.TaskCollection";
454bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["@odata.id"] =
455bd79bce8SPatrick Williams                     "/redfish/v1/TaskService/Tasks";
45646229577SJames Feist                 asyncResp->res.jsonValue["Name"] = "Task Collection";
457bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
458bd79bce8SPatrick Williams                     task::tasks.size();
45946229577SJames Feist                 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
46046229577SJames Feist                 members = nlohmann::json::array();
46146229577SJames Feist 
46246229577SJames Feist                 for (const std::shared_ptr<task::TaskData>& task : task::tasks)
46346229577SJames Feist                 {
46446229577SJames Feist                     if (task == nullptr)
46546229577SJames Feist                     {
46646229577SJames Feist                         continue; // shouldn't be possible
46746229577SJames Feist                     }
468613dabeaSEd Tanous                     nlohmann::json::object_t member;
469ef4c65b7SEd Tanous                     member["@odata.id"] =
470ef4c65b7SEd Tanous                         boost::urls::format("/redfish/v1/TaskService/Tasks/{}",
471eddfc437SWilly Tu                                             std::to_string(task->index));
472613dabeaSEd Tanous                     members.emplace_back(std::move(member));
47346229577SJames Feist                 }
4747e860f15SJohn Edward Broadbent             });
47546229577SJames Feist }
47646229577SJames Feist 
4777e860f15SJohn Edward Broadbent inline void requestRoutesTaskService(App& app)
47846229577SJames Feist {
4797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/TaskService/")
480ed398213SEd Tanous         .privileges(redfish::privileges::getTaskService)
4817e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
48245ca1b86SEd Tanous             [&app](const crow::Request& req,
4837e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
4843ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
48545ca1b86SEd Tanous                 {
48645ca1b86SEd Tanous                     return;
48745ca1b86SEd Tanous                 }
48846229577SJames Feist                 asyncResp->res.jsonValue["@odata.type"] =
48946229577SJames Feist                     "#TaskService.v1_1_4.TaskService";
490bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["@odata.id"] =
491bd79bce8SPatrick Williams                     "/redfish/v1/TaskService";
49246229577SJames Feist                 asyncResp->res.jsonValue["Name"] = "Task Service";
49346229577SJames Feist                 asyncResp->res.jsonValue["Id"] = "TaskService";
4947e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DateTime"] =
4952b82937eSEd Tanous                     redfish::time_utils::getDateTimeOffsetNow().first;
496539d8c6bSEd Tanous                 asyncResp->res.jsonValue["CompletedTaskOverWritePolicy"] =
497539d8c6bSEd Tanous                     task_service::OverWritePolicy::Oldest;
49846229577SJames Feist 
499bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] =
500bd79bce8SPatrick Williams                     true;
50146229577SJames Feist 
502bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Status"]["State"] =
503bd79bce8SPatrick Williams                     resource::State::Enabled;
50446229577SJames Feist                 asyncResp->res.jsonValue["ServiceEnabled"] = true;
5051476687dSEd Tanous                 asyncResp->res.jsonValue["Tasks"]["@odata.id"] =
5061476687dSEd Tanous                     "/redfish/v1/TaskService/Tasks";
5077e860f15SJohn Edward Broadbent             });
50846229577SJames Feist }
50946229577SJames Feist 
51046229577SJames Feist } // namespace redfish
511