140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation 446229577SJames Feist #pragma once 546229577SJames Feist 63ccb3adbSEd Tanous #include "app.hpp" 7*d7857201SEd Tanous #include "async_resp.hpp" 8*d7857201SEd Tanous #include "dbus_singleton.hpp" 9*d7857201SEd Tanous #include "error_messages.hpp" 103ccb3adbSEd Tanous #include "event_service_manager.hpp" 11539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 12539d8c6bSEd Tanous #include "generated/enums/task_service.hpp" 131aa0c2b8SEd Tanous #include "http/parsing.hpp" 14*d7857201SEd Tanous #include "http_request.hpp" 15*d7857201SEd Tanous #include "http_response.hpp" 16*d7857201SEd Tanous #include "logging.hpp" 173ccb3adbSEd Tanous #include "query.hpp" 183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 193ccb3adbSEd Tanous #include "task_messages.hpp" 20*d7857201SEd Tanous #include "utils/time_utils.hpp" 213ccb3adbSEd Tanous 22*d7857201SEd Tanous #include <boost/asio/error.hpp> 23d43cd0caSEd Tanous #include <boost/asio/post.hpp> 24d43cd0caSEd Tanous #include <boost/asio/steady_timer.hpp> 25*d7857201SEd Tanous #include <boost/beast/http/field.hpp> 26*d7857201SEd Tanous #include <boost/beast/http/status.hpp> 27*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 28ef4c65b7SEd Tanous #include <boost/url/format.hpp> 29*d7857201SEd Tanous #include <boost/url/url.hpp> 30*d7857201SEd Tanous #include <nlohmann/json.hpp> 31*d7857201SEd Tanous #include <sdbusplus/bus.hpp> 323ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp> 33*d7857201SEd Tanous #include <sdbusplus/message.hpp> 341214b7e7SGunnar Mills 35*d7857201SEd Tanous #include <algorithm> 36*d7857201SEd Tanous #include <array> 371214b7e7SGunnar Mills #include <chrono> 38*d7857201SEd Tanous #include <cstddef> 39*d7857201SEd Tanous #include <ctime> 40*d7857201SEd Tanous #include <deque> 41*d7857201SEd Tanous #include <functional> 423ccb3adbSEd Tanous #include <memory> 43*d7857201SEd Tanous #include <optional> 443544d2a7SEd Tanous #include <ranges> 45*d7857201SEd Tanous #include <string> 46*d7857201SEd Tanous #include <string_view> 47*d7857201SEd Tanous #include <utility> 4846229577SJames Feist 4946229577SJames Feist namespace redfish 5046229577SJames Feist { 5146229577SJames Feist 5246229577SJames Feist namespace task 5346229577SJames Feist { 5446229577SJames Feist constexpr size_t maxTaskCount = 100; // arbitrary limit 5546229577SJames Feist 56cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 5746229577SJames Feist static std::deque<std::shared_ptr<struct TaskData>> tasks; 5846229577SJames Feist 5932898ceaSJames Feist constexpr bool completed = true; 6032898ceaSJames Feist 61fe306728SJames Feist struct Payload 62fe306728SJames Feist { 634e23a444SEd Tanous explicit Payload(const crow::Request& req) : 6439662a3bSEd Tanous targetUri(req.url().encoded_path()), httpOperation(req.methodString()), 651aa0c2b8SEd Tanous httpHeaders(nlohmann::json::array()) 66fe306728SJames Feist { 67fe306728SJames Feist using field_ns = boost::beast::http::field; 68fe306728SJames Feist constexpr const std::array<boost::beast::http::field, 7> 69fe306728SJames Feist headerWhitelist = {field_ns::accept, field_ns::accept_encoding, 70fe306728SJames Feist field_ns::user_agent, field_ns::host, 71fe306728SJames Feist field_ns::connection, field_ns::content_length, 72fe306728SJames Feist field_ns::upgrade}; 73fe306728SJames Feist 741aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, jsonBody); 751aa0c2b8SEd Tanous if (ret != JsonParseResult::Success) 76fe306728SJames Feist { 771aa0c2b8SEd Tanous return; 78fe306728SJames Feist } 79fe306728SJames Feist 8098fe740bSEd Tanous for (const auto& field : req.fields()) 81fe306728SJames Feist { 823544d2a7SEd Tanous if (std::ranges::find(headerWhitelist, field.name()) == 833544d2a7SEd Tanous headerWhitelist.end()) 84fe306728SJames Feist { 85fe306728SJames Feist continue; 86fe306728SJames Feist } 87fe306728SJames Feist std::string header; 88bd79bce8SPatrick Williams header.reserve( 89bd79bce8SPatrick Williams field.name_string().size() + 2 + field.value().size()); 90fe306728SJames Feist header += field.name_string(); 91fe306728SJames Feist header += ": "; 92fe306728SJames Feist header += field.value(); 93fe306728SJames Feist httpHeaders.emplace_back(std::move(header)); 94fe306728SJames Feist } 95fe306728SJames Feist } 96fe306728SJames Feist Payload() = delete; 97fe306728SJames Feist 98fe306728SJames Feist std::string targetUri; 99fe306728SJames Feist std::string httpOperation; 100fe306728SJames Feist nlohmann::json httpHeaders; 101fe306728SJames Feist nlohmann::json jsonBody; 102fe306728SJames Feist }; 103fe306728SJames Feist 10446229577SJames Feist struct TaskData : std::enable_shared_from_this<TaskData> 10546229577SJames Feist { 10646229577SJames Feist private: 10759d494eeSPatrick Williams TaskData( 10859d494eeSPatrick Williams std::function<bool(boost::system::error_code, sdbusplus::message_t&, 10946229577SJames Feist const std::shared_ptr<TaskData>&)>&& handler, 11023a21a1cSEd Tanous const std::string& matchIn, size_t idx) : 111bd79bce8SPatrick Williams callback(std::move(handler)), matchStr(matchIn), index(idx), 11246229577SJames Feist startTime(std::chrono::system_clock::to_time_t( 11346229577SJames Feist std::chrono::system_clock::now())), 11446229577SJames Feist status("OK"), state("Running"), messages(nlohmann::json::array()), 11546229577SJames Feist timer(crow::connections::systemBus->get_io_context()) 11646229577SJames Feist 1171214b7e7SGunnar Mills {} 11846229577SJames Feist 11946229577SJames Feist public: 120d609fd6eSEd Tanous TaskData() = delete; 121d609fd6eSEd Tanous 12246229577SJames Feist static std::shared_ptr<TaskData>& createTask( 12359d494eeSPatrick Williams std::function<bool(boost::system::error_code, sdbusplus::message_t&, 12446229577SJames Feist const std::shared_ptr<TaskData>&)>&& handler, 12546229577SJames Feist const std::string& match) 12646229577SJames Feist { 12746229577SJames Feist static size_t lastTask = 0; 12846229577SJames Feist struct MakeSharedHelper : public TaskData 12946229577SJames Feist { 13046229577SJames Feist MakeSharedHelper( 1311214b7e7SGunnar Mills std::function<bool(boost::system::error_code, 13259d494eeSPatrick Williams sdbusplus::message_t&, 13346229577SJames Feist const std::shared_ptr<TaskData>&)>&& handler, 13423a21a1cSEd Tanous const std::string& match2, size_t idx) : 13523a21a1cSEd Tanous TaskData(std::move(handler), match2, idx) 1361214b7e7SGunnar Mills {} 13746229577SJames Feist }; 13846229577SJames Feist 13946229577SJames Feist if (tasks.size() >= maxTaskCount) 14046229577SJames Feist { 14102cad96eSEd Tanous const auto& last = tasks.front(); 14246229577SJames Feist 14346229577SJames Feist // destroy all references 14446229577SJames Feist last->timer.cancel(); 14546229577SJames Feist last->match.reset(); 14646229577SJames Feist tasks.pop_front(); 14746229577SJames Feist } 14846229577SJames Feist 14946229577SJames Feist return tasks.emplace_back(std::make_shared<MakeSharedHelper>( 15046229577SJames Feist std::move(handler), match, lastTask++)); 15146229577SJames Feist } 15246229577SJames Feist 15346229577SJames Feist void populateResp(crow::Response& res, size_t retryAfterSeconds = 30) 15446229577SJames Feist { 15546229577SJames Feist if (!endTime) 15646229577SJames Feist { 15746229577SJames Feist res.result(boost::beast::http::status::accepted); 15846229577SJames Feist std::string strIdx = std::to_string(index); 159fdbce79bSEd Tanous boost::urls::url uri = 160fdbce79bSEd Tanous boost::urls::format("/redfish/v1/TaskService/Tasks/{}", strIdx); 1611476687dSEd Tanous 1621476687dSEd Tanous res.jsonValue["@odata.id"] = uri; 1631476687dSEd Tanous res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task"; 1641476687dSEd Tanous res.jsonValue["Id"] = strIdx; 1651476687dSEd Tanous res.jsonValue["TaskState"] = state; 1661476687dSEd Tanous res.jsonValue["TaskStatus"] = status; 1671476687dSEd Tanous 168fdbce79bSEd Tanous boost::urls::url taskMonitor = boost::urls::format( 169fdbce79bSEd Tanous "/redfish/v1/TaskService/TaskMonitors/{}", strIdx); 170fdbce79bSEd Tanous 17146229577SJames Feist res.addHeader(boost::beast::http::field::location, 172fdbce79bSEd Tanous taskMonitor.buffer()); 17346229577SJames Feist res.addHeader(boost::beast::http::field::retry_after, 17446229577SJames Feist std::to_string(retryAfterSeconds)); 17546229577SJames Feist } 17646229577SJames Feist else if (!gave204) 17746229577SJames Feist { 17846229577SJames Feist res.result(boost::beast::http::status::no_content); 17946229577SJames Feist gave204 = true; 18046229577SJames Feist } 18146229577SJames Feist } 18246229577SJames Feist 183d609fd6eSEd Tanous void finishTask() 18446229577SJames Feist { 18546229577SJames Feist endTime = std::chrono::system_clock::to_time_t( 18646229577SJames Feist std::chrono::system_clock::now()); 18746229577SJames Feist } 18846229577SJames Feist 189fd9ab9e1SJames Feist void extendTimer(const std::chrono::seconds& timeout) 19046229577SJames Feist { 19146229577SJames Feist timer.expires_after(timeout); 19246229577SJames Feist timer.async_wait( 19346229577SJames Feist [self = shared_from_this()](boost::system::error_code ec) { 19446229577SJames Feist if (ec == boost::asio::error::operation_aborted) 19546229577SJames Feist { 1964e0453b1SGunnar Mills return; // completed successfully 19746229577SJames Feist } 19846229577SJames Feist if (!ec) 19946229577SJames Feist { 20046229577SJames Feist // change ec to error as timer expired 20146229577SJames Feist ec = boost::asio::error::operation_aborted; 20246229577SJames Feist } 20346229577SJames Feist self->match.reset(); 20459d494eeSPatrick Williams sdbusplus::message_t msg; 20546229577SJames Feist self->finishTask(); 20646229577SJames Feist self->state = "Cancelled"; 20746229577SJames Feist self->status = "Warning"; 208e5d5006bSJames Feist self->messages.emplace_back( 209e5d5006bSJames Feist messages::taskAborted(std::to_string(self->index))); 210e7686576SSunitha Harish // Send event :TaskAborted 211daadfb2eSEd Tanous sendTaskEvent(self->state, self->index); 21246229577SJames Feist self->callback(ec, msg, self); 21346229577SJames Feist }); 214fd9ab9e1SJames Feist } 215fd9ab9e1SJames Feist 21626ccae32SEd Tanous static void sendTaskEvent(std::string_view state, size_t index) 217e7686576SSunitha Harish { 218e7686576SSunitha Harish // TaskState enums which should send out an event are: 219e7686576SSunitha Harish // "Starting" = taskResumed 220e7686576SSunitha Harish // "Running" = taskStarted 221e7686576SSunitha Harish // "Suspended" = taskPaused 222e7686576SSunitha Harish // "Interrupted" = taskPaused 223e7686576SSunitha Harish // "Pending" = taskPaused 224e7686576SSunitha Harish // "Stopping" = taskAborted 225e7686576SSunitha Harish // "Completed" = taskCompletedOK 226e7686576SSunitha Harish // "Killed" = taskRemoved 227e7686576SSunitha Harish // "Exception" = taskCompletedWarning 228e7686576SSunitha Harish // "Cancelled" = taskCancelled 229f8fe2211SEd Tanous nlohmann::json event; 230f8fe2211SEd Tanous std::string indexStr = std::to_string(index); 231e7686576SSunitha Harish if (state == "Starting") 232e7686576SSunitha Harish { 233f8fe2211SEd Tanous event = redfish::messages::taskResumed(indexStr); 234e7686576SSunitha Harish } 235e7686576SSunitha Harish else if (state == "Running") 236e7686576SSunitha Harish { 237f8fe2211SEd Tanous event = redfish::messages::taskStarted(indexStr); 238e7686576SSunitha Harish } 239e7686576SSunitha Harish else if ((state == "Suspended") || (state == "Interrupted") || 240e7686576SSunitha Harish (state == "Pending")) 241e7686576SSunitha Harish { 242f8fe2211SEd Tanous event = redfish::messages::taskPaused(indexStr); 243e7686576SSunitha Harish } 244e7686576SSunitha Harish else if (state == "Stopping") 245e7686576SSunitha Harish { 246f8fe2211SEd Tanous event = redfish::messages::taskAborted(indexStr); 247e7686576SSunitha Harish } 248e7686576SSunitha Harish else if (state == "Completed") 249e7686576SSunitha Harish { 250f8fe2211SEd Tanous event = redfish::messages::taskCompletedOK(indexStr); 251e7686576SSunitha Harish } 252e7686576SSunitha Harish else if (state == "Killed") 253e7686576SSunitha Harish { 254f8fe2211SEd Tanous event = redfish::messages::taskRemoved(indexStr); 255e7686576SSunitha Harish } 256e7686576SSunitha Harish else if (state == "Exception") 257e7686576SSunitha Harish { 258f8fe2211SEd Tanous event = redfish::messages::taskCompletedWarning(indexStr); 259e7686576SSunitha Harish } 260e7686576SSunitha Harish else if (state == "Cancelled") 261e7686576SSunitha Harish { 262f8fe2211SEd Tanous event = redfish::messages::taskCancelled(indexStr); 263e7686576SSunitha Harish } 264e7686576SSunitha Harish else 265e7686576SSunitha Harish { 26662598e31SEd Tanous BMCWEB_LOG_INFO("sendTaskEvent: No events to send"); 267f8fe2211SEd Tanous return; 268e7686576SSunitha Harish } 269f8fe2211SEd Tanous boost::urls::url origin = 270f8fe2211SEd Tanous boost::urls::format("/redfish/v1/TaskService/Tasks/{}", index); 271f8fe2211SEd Tanous EventServiceManager::getInstance().sendEvent(event, origin.buffer(), 272f8fe2211SEd Tanous "Task"); 273e7686576SSunitha Harish } 274e7686576SSunitha Harish 275fd9ab9e1SJames Feist void startTimer(const std::chrono::seconds& timeout) 276fd9ab9e1SJames Feist { 277fd9ab9e1SJames Feist if (match) 278fd9ab9e1SJames Feist { 279fd9ab9e1SJames Feist return; 280fd9ab9e1SJames Feist } 28159d494eeSPatrick Williams match = std::make_unique<sdbusplus::bus::match_t>( 28259d494eeSPatrick Williams static_cast<sdbusplus::bus_t&>(*crow::connections::systemBus), 283fd9ab9e1SJames Feist matchStr, 28459d494eeSPatrick Williams [self = shared_from_this()](sdbusplus::message_t& message) { 285fd9ab9e1SJames Feist boost::system::error_code ec; 286fd9ab9e1SJames Feist 287fd9ab9e1SJames Feist // callback to return True if callback is done, callback needs 288fd9ab9e1SJames Feist // to update status itself if needed 289fd9ab9e1SJames Feist if (self->callback(ec, message, self) == task::completed) 290fd9ab9e1SJames Feist { 291fd9ab9e1SJames Feist self->timer.cancel(); 292fd9ab9e1SJames Feist self->finishTask(); 293fd9ab9e1SJames Feist 294e7686576SSunitha Harish // Send event 295daadfb2eSEd Tanous sendTaskEvent(self->state, self->index); 296e7686576SSunitha Harish 297fd9ab9e1SJames Feist // reset the match after the callback was successful 298fd9ab9e1SJames Feist boost::asio::post( 299fd9ab9e1SJames Feist crow::connections::systemBus->get_io_context(), 300fd9ab9e1SJames Feist [self] { self->match.reset(); }); 301fd9ab9e1SJames Feist return; 302fd9ab9e1SJames Feist } 303fd9ab9e1SJames Feist }); 304fd9ab9e1SJames Feist 305fd9ab9e1SJames Feist extendTimer(timeout); 306e5d5006bSJames Feist messages.emplace_back(messages::taskStarted(std::to_string(index))); 307e7686576SSunitha Harish // Send event : TaskStarted 308e7686576SSunitha Harish sendTaskEvent(state, index); 30946229577SJames Feist } 31046229577SJames Feist 31159d494eeSPatrick Williams std::function<bool(boost::system::error_code, sdbusplus::message_t&, 31246229577SJames Feist const std::shared_ptr<TaskData>&)> 31346229577SJames Feist callback; 31446229577SJames Feist std::string matchStr; 31546229577SJames Feist size_t index; 31646229577SJames Feist time_t startTime; 31746229577SJames Feist std::string status; 31846229577SJames Feist std::string state; 31946229577SJames Feist nlohmann::json messages; 32046229577SJames Feist boost::asio::steady_timer timer; 32159d494eeSPatrick Williams std::unique_ptr<sdbusplus::bus::match_t> match; 32246229577SJames Feist std::optional<time_t> endTime; 323fe306728SJames Feist std::optional<Payload> payload; 32446229577SJames Feist bool gave204 = false; 3256868ff50SGeorge Liu int percentComplete = 0; 32646229577SJames Feist }; 32746229577SJames Feist 32846229577SJames Feist } // namespace task 32946229577SJames Feist 3307e860f15SJohn Edward Broadbent inline void requestRoutesTaskMonitor(App& app) 33146229577SJames Feist { 332fdbce79bSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/TaskService/TaskMonitors/<str>/") 333ed398213SEd Tanous .privileges(redfish::privileges::getTask) 3347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 33545ca1b86SEd Tanous [&app](const crow::Request& req, 3367e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3377e860f15SJohn Edward Broadbent const std::string& strParam) { 3383ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 33945ca1b86SEd Tanous { 34045ca1b86SEd Tanous return; 34145ca1b86SEd Tanous } 3423544d2a7SEd Tanous auto find = std::ranges::find_if( 3433544d2a7SEd Tanous task::tasks, 34446229577SJames Feist [&strParam](const std::shared_ptr<task::TaskData>& task) { 34546229577SJames Feist if (!task) 34646229577SJames Feist { 34746229577SJames Feist return false; 34846229577SJames Feist } 34946229577SJames Feist 3507e860f15SJohn Edward Broadbent // we compare against the string version as on failure 3517e860f15SJohn Edward Broadbent // strtoul returns 0 35246229577SJames Feist return std::to_string(task->index) == strParam; 35346229577SJames Feist }); 35446229577SJames Feist 35546229577SJames Feist if (find == task::tasks.end()) 35646229577SJames Feist { 357bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Task", 358bd79bce8SPatrick Williams strParam); 35946229577SJames Feist return; 36046229577SJames Feist } 36146229577SJames Feist std::shared_ptr<task::TaskData>& ptr = *find; 36246229577SJames Feist // monitor expires after 204 36346229577SJames Feist if (ptr->gave204) 36446229577SJames Feist { 365bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Task", 366bd79bce8SPatrick Williams strParam); 36746229577SJames Feist return; 36846229577SJames Feist } 36946229577SJames Feist ptr->populateResp(asyncResp->res); 3707e860f15SJohn Edward Broadbent }); 37146229577SJames Feist } 37246229577SJames Feist 3737e860f15SJohn Edward Broadbent inline void requestRoutesTask(App& app) 37446229577SJames Feist { 3757e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/<str>/") 376ed398213SEd Tanous .privileges(redfish::privileges::getTask) 3777e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 37845ca1b86SEd Tanous [&app](const crow::Request& req, 3797e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3807e860f15SJohn Edward Broadbent const std::string& strParam) { 3813ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 38245ca1b86SEd Tanous { 38345ca1b86SEd Tanous return; 38445ca1b86SEd Tanous } 3853544d2a7SEd Tanous auto find = std::ranges::find_if( 3863544d2a7SEd Tanous task::tasks, 38746229577SJames Feist [&strParam](const std::shared_ptr<task::TaskData>& task) { 38846229577SJames Feist if (!task) 38946229577SJames Feist { 39046229577SJames Feist return false; 39146229577SJames Feist } 39246229577SJames Feist 3937e860f15SJohn Edward Broadbent // we compare against the string version as on failure 3947e860f15SJohn Edward Broadbent // strtoul returns 0 39546229577SJames Feist return std::to_string(task->index) == strParam; 39646229577SJames Feist }); 39746229577SJames Feist 39846229577SJames Feist if (find == task::tasks.end()) 39946229577SJames Feist { 400bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Task", 401bd79bce8SPatrick Williams strParam); 40246229577SJames Feist return; 40346229577SJames Feist } 40446229577SJames Feist 40502cad96eSEd Tanous const std::shared_ptr<task::TaskData>& ptr = *find; 40646229577SJames Feist 40746229577SJames Feist asyncResp->res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task"; 40846229577SJames Feist asyncResp->res.jsonValue["Id"] = strParam; 40946229577SJames Feist asyncResp->res.jsonValue["Name"] = "Task " + strParam; 41046229577SJames Feist asyncResp->res.jsonValue["TaskState"] = ptr->state; 41146229577SJames Feist asyncResp->res.jsonValue["StartTime"] = 4122b82937eSEd Tanous redfish::time_utils::getDateTimeStdtime(ptr->startTime); 41346229577SJames Feist if (ptr->endTime) 41446229577SJames Feist { 41546229577SJames Feist asyncResp->res.jsonValue["EndTime"] = 416bd79bce8SPatrick Williams redfish::time_utils::getDateTimeStdtime( 417bd79bce8SPatrick Williams *(ptr->endTime)); 41846229577SJames Feist } 41946229577SJames Feist asyncResp->res.jsonValue["TaskStatus"] = ptr->status; 42046229577SJames Feist asyncResp->res.jsonValue["Messages"] = ptr->messages; 421bd79bce8SPatrick Williams asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 422bd79bce8SPatrick Williams "/redfish/v1/TaskService/Tasks/{}", strParam); 42346229577SJames Feist if (!ptr->gave204) 42446229577SJames Feist { 425bd79bce8SPatrick Williams asyncResp->res.jsonValue["TaskMonitor"] = 426bd79bce8SPatrick Williams boost::urls::format( 427bd79bce8SPatrick Williams "/redfish/v1/TaskService/TaskMonitors/{}", 428bd79bce8SPatrick Williams strParam); 42946229577SJames Feist } 4305db7dfd6SArun Thomas Baby 4315db7dfd6SArun Thomas Baby asyncResp->res.jsonValue["HidePayload"] = !ptr->payload; 4325db7dfd6SArun Thomas Baby 433fe306728SJames Feist if (ptr->payload) 434fe306728SJames Feist { 4355fb91ba4SEd Tanous const task::Payload& p = *(ptr->payload); 436bd79bce8SPatrick Williams asyncResp->res.jsonValue["Payload"]["TargetUri"] = 437bd79bce8SPatrick Williams p.targetUri; 4381476687dSEd Tanous asyncResp->res.jsonValue["Payload"]["HttpOperation"] = 4391476687dSEd Tanous p.httpOperation; 440bd79bce8SPatrick Williams asyncResp->res.jsonValue["Payload"]["HttpHeaders"] = 441bd79bce8SPatrick Williams p.httpHeaders; 442bd79bce8SPatrick Williams asyncResp->res.jsonValue["Payload"]["JsonBody"] = 443bd79bce8SPatrick Williams p.jsonBody.dump( 444bd79bce8SPatrick Williams -1, ' ', true, 445bd79bce8SPatrick Williams nlohmann::json::error_handler_t::replace); 446fe306728SJames Feist } 447bd79bce8SPatrick Williams asyncResp->res.jsonValue["PercentComplete"] = 448bd79bce8SPatrick Williams ptr->percentComplete; 4497e860f15SJohn Edward Broadbent }); 45046229577SJames Feist } 45146229577SJames Feist 4527e860f15SJohn Edward Broadbent inline void requestRoutesTaskCollection(App& app) 45346229577SJames Feist { 4547e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/") 455ed398213SEd Tanous .privileges(redfish::privileges::getTaskCollection) 4567e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 45745ca1b86SEd Tanous [&app](const crow::Request& req, 4587e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 4593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 46045ca1b86SEd Tanous { 46145ca1b86SEd Tanous return; 46245ca1b86SEd Tanous } 46346229577SJames Feist asyncResp->res.jsonValue["@odata.type"] = 46446229577SJames Feist "#TaskCollection.TaskCollection"; 465bd79bce8SPatrick Williams asyncResp->res.jsonValue["@odata.id"] = 466bd79bce8SPatrick Williams "/redfish/v1/TaskService/Tasks"; 46746229577SJames Feist asyncResp->res.jsonValue["Name"] = "Task Collection"; 468bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 469bd79bce8SPatrick Williams task::tasks.size(); 47046229577SJames Feist nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 47146229577SJames Feist members = nlohmann::json::array(); 47246229577SJames Feist 47346229577SJames Feist for (const std::shared_ptr<task::TaskData>& task : task::tasks) 47446229577SJames Feist { 47546229577SJames Feist if (task == nullptr) 47646229577SJames Feist { 47746229577SJames Feist continue; // shouldn't be possible 47846229577SJames Feist } 479613dabeaSEd Tanous nlohmann::json::object_t member; 480ef4c65b7SEd Tanous member["@odata.id"] = 481ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/TaskService/Tasks/{}", 482eddfc437SWilly Tu std::to_string(task->index)); 483613dabeaSEd Tanous members.emplace_back(std::move(member)); 48446229577SJames Feist } 4857e860f15SJohn Edward Broadbent }); 48646229577SJames Feist } 48746229577SJames Feist 4887e860f15SJohn Edward Broadbent inline void requestRoutesTaskService(App& app) 48946229577SJames Feist { 4907e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/") 491ed398213SEd Tanous .privileges(redfish::privileges::getTaskService) 4927e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 49345ca1b86SEd Tanous [&app](const crow::Request& req, 4947e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 4953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49645ca1b86SEd Tanous { 49745ca1b86SEd Tanous return; 49845ca1b86SEd Tanous } 49946229577SJames Feist asyncResp->res.jsonValue["@odata.type"] = 50046229577SJames Feist "#TaskService.v1_1_4.TaskService"; 501bd79bce8SPatrick Williams asyncResp->res.jsonValue["@odata.id"] = 502bd79bce8SPatrick Williams "/redfish/v1/TaskService"; 50346229577SJames Feist asyncResp->res.jsonValue["Name"] = "Task Service"; 50446229577SJames Feist asyncResp->res.jsonValue["Id"] = "TaskService"; 5057e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DateTime"] = 5062b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 507539d8c6bSEd Tanous asyncResp->res.jsonValue["CompletedTaskOverWritePolicy"] = 508539d8c6bSEd Tanous task_service::OverWritePolicy::Oldest; 50946229577SJames Feist 510bd79bce8SPatrick Williams asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] = 511bd79bce8SPatrick Williams true; 51246229577SJames Feist 513bd79bce8SPatrick Williams asyncResp->res.jsonValue["Status"]["State"] = 514bd79bce8SPatrick Williams resource::State::Enabled; 51546229577SJames Feist asyncResp->res.jsonValue["ServiceEnabled"] = true; 5161476687dSEd Tanous asyncResp->res.jsonValue["Tasks"]["@odata.id"] = 5171476687dSEd Tanous "/redfish/v1/TaskService/Tasks"; 5187e860f15SJohn Edward Broadbent }); 51946229577SJames Feist } 52046229577SJames Feist 52146229577SJames Feist } // namespace redfish 522