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