146229577SJames Feist /* 2*6be832e2SEd Tanous Copyright (c) 2020 Intel Corporation 3*6be832e2SEd Tanous 4*6be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 5*6be832e2SEd Tanous you may not use this file except in compliance with the License. 6*6be832e2SEd Tanous You may obtain a copy of the License at 7*6be832e2SEd Tanous 8*6be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 9*6be832e2SEd Tanous 10*6be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 11*6be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 12*6be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6be832e2SEd Tanous See the License for the specific language governing permissions and 14*6be832e2SEd 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 200e7686576SSunitha Harish self->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 284e7686576SSunitha Harish self->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