146229577SJames Feist /* 246229577SJames Feist // Copyright (c) 2020 Intel Corporation 346229577SJames Feist // 446229577SJames Feist // Licensed under the Apache License, Version 2.0 (the "License"); 546229577SJames Feist // you may not use this file except in compliance with the License. 646229577SJames Feist // You may obtain a copy of the License at 746229577SJames Feist // 846229577SJames Feist // http://www.apache.org/licenses/LICENSE-2.0 946229577SJames Feist // 1046229577SJames Feist // Unless required by applicable law or agreed to in writing, software 1146229577SJames Feist // distributed under the License is distributed on an "AS IS" BASIS, 1246229577SJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1346229577SJames Feist // See the License for the specific language governing permissions and 1446229577SJames Feist // limitations under the License. 1546229577SJames Feist */ 1646229577SJames Feist #pragma once 1746229577SJames Feist 187e860f15SJohn Edward Broadbent #include <app.hpp> 19d43cd0caSEd Tanous #include <boost/asio/post.hpp> 20d43cd0caSEd Tanous #include <boost/asio/steady_timer.hpp> 2146229577SJames Feist #include <boost/container/flat_map.hpp> 22ed398213SEd Tanous #include <registries/privilege_registry.hpp> 23e5d5006bSJames Feist #include <task_messages.hpp> 241214b7e7SGunnar Mills 251214b7e7SGunnar Mills #include <chrono> 2646229577SJames Feist #include <variant> 2746229577SJames Feist 2846229577SJames Feist namespace redfish 2946229577SJames Feist { 3046229577SJames Feist 3146229577SJames Feist namespace task 3246229577SJames Feist { 3346229577SJames Feist constexpr size_t maxTaskCount = 100; // arbitrary limit 3446229577SJames Feist 3546229577SJames Feist static std::deque<std::shared_ptr<struct TaskData>> tasks; 3646229577SJames Feist 3732898ceaSJames Feist constexpr bool completed = true; 3832898ceaSJames Feist 39fe306728SJames Feist struct Payload 40fe306728SJames Feist { 41fe306728SJames Feist Payload(const crow::Request& req) : 42fe306728SJames Feist targetUri(req.url), httpOperation(req.methodString()), 43fe306728SJames Feist httpHeaders(nlohmann::json::array()) 44fe306728SJames Feist 45fe306728SJames Feist { 46fe306728SJames Feist using field_ns = boost::beast::http::field; 47fe306728SJames Feist constexpr const std::array<boost::beast::http::field, 7> 48fe306728SJames Feist headerWhitelist = {field_ns::accept, field_ns::accept_encoding, 49fe306728SJames Feist field_ns::user_agent, field_ns::host, 50fe306728SJames Feist field_ns::connection, field_ns::content_length, 51fe306728SJames Feist field_ns::upgrade}; 52fe306728SJames Feist 53fe306728SJames Feist jsonBody = nlohmann::json::parse(req.body, nullptr, false); 54fe306728SJames Feist if (jsonBody.is_discarded()) 55fe306728SJames Feist { 56fe306728SJames Feist jsonBody = nullptr; 57fe306728SJames Feist } 58fe306728SJames Feist 59fe306728SJames Feist for (const auto& field : req.fields) 60fe306728SJames Feist { 61fe306728SJames Feist if (std::find(headerWhitelist.begin(), headerWhitelist.end(), 62fe306728SJames Feist field.name()) == headerWhitelist.end()) 63fe306728SJames Feist { 64fe306728SJames Feist continue; 65fe306728SJames Feist } 66fe306728SJames Feist std::string header; 67fe306728SJames Feist header.reserve(field.name_string().size() + 2 + 68fe306728SJames Feist field.value().size()); 69fe306728SJames Feist header += field.name_string(); 70fe306728SJames Feist header += ": "; 71fe306728SJames Feist header += field.value(); 72fe306728SJames Feist httpHeaders.emplace_back(std::move(header)); 73fe306728SJames Feist } 74fe306728SJames Feist } 75fe306728SJames Feist Payload() = delete; 76fe306728SJames Feist 77fe306728SJames Feist std::string targetUri; 78fe306728SJames Feist std::string httpOperation; 79fe306728SJames Feist nlohmann::json httpHeaders; 80fe306728SJames Feist nlohmann::json jsonBody; 81fe306728SJames Feist }; 82fe306728SJames Feist 8346229577SJames Feist struct TaskData : std::enable_shared_from_this<TaskData> 8446229577SJames Feist { 8546229577SJames Feist private: 8646229577SJames Feist TaskData(std::function<bool(boost::system::error_code, 8746229577SJames Feist sdbusplus::message::message&, 8846229577SJames Feist const std::shared_ptr<TaskData>&)>&& handler, 8923a21a1cSEd Tanous const std::string& matchIn, size_t idx) : 9046229577SJames Feist callback(std::move(handler)), 9123a21a1cSEd Tanous matchStr(matchIn), index(idx), 9246229577SJames Feist startTime(std::chrono::system_clock::to_time_t( 9346229577SJames Feist std::chrono::system_clock::now())), 9446229577SJames Feist status("OK"), state("Running"), messages(nlohmann::json::array()), 9546229577SJames Feist timer(crow::connections::systemBus->get_io_context()) 9646229577SJames Feist 971214b7e7SGunnar Mills {} 9846229577SJames Feist 9946229577SJames Feist public: 100d609fd6eSEd Tanous TaskData() = delete; 101d609fd6eSEd Tanous 10246229577SJames Feist static std::shared_ptr<TaskData>& createTask( 10346229577SJames Feist std::function<bool(boost::system::error_code, 10446229577SJames Feist sdbusplus::message::message&, 10546229577SJames Feist const std::shared_ptr<TaskData>&)>&& handler, 10646229577SJames Feist const std::string& match) 10746229577SJames Feist { 10846229577SJames Feist static size_t lastTask = 0; 10946229577SJames Feist struct MakeSharedHelper : public TaskData 11046229577SJames Feist { 11146229577SJames Feist MakeSharedHelper( 1121214b7e7SGunnar Mills std::function<bool(boost::system::error_code, 1131214b7e7SGunnar Mills sdbusplus::message::message&, 11446229577SJames Feist const std::shared_ptr<TaskData>&)>&& handler, 11523a21a1cSEd Tanous const std::string& match2, size_t idx) : 11623a21a1cSEd Tanous TaskData(std::move(handler), match2, idx) 1171214b7e7SGunnar Mills {} 11846229577SJames Feist }; 11946229577SJames Feist 12046229577SJames Feist if (tasks.size() >= maxTaskCount) 12146229577SJames Feist { 12246229577SJames Feist auto& last = tasks.front(); 12346229577SJames Feist 12446229577SJames Feist // destroy all references 12546229577SJames Feist last->timer.cancel(); 12646229577SJames Feist last->match.reset(); 12746229577SJames Feist tasks.pop_front(); 12846229577SJames Feist } 12946229577SJames Feist 13046229577SJames Feist return tasks.emplace_back(std::make_shared<MakeSharedHelper>( 13146229577SJames Feist std::move(handler), match, lastTask++)); 13246229577SJames Feist } 13346229577SJames Feist 13446229577SJames Feist void populateResp(crow::Response& res, size_t retryAfterSeconds = 30) 13546229577SJames Feist { 13646229577SJames Feist if (!endTime) 13746229577SJames Feist { 13846229577SJames Feist res.result(boost::beast::http::status::accepted); 13946229577SJames Feist std::string strIdx = std::to_string(index); 14046229577SJames Feist std::string uri = "/redfish/v1/TaskService/Tasks/" + strIdx; 14146229577SJames Feist res.jsonValue = {{"@odata.id", uri}, 14246229577SJames Feist {"@odata.type", "#Task.v1_4_3.Task"}, 14346229577SJames Feist {"Id", strIdx}, 14446229577SJames Feist {"TaskState", state}, 14546229577SJames Feist {"TaskStatus", status}}; 14646229577SJames Feist res.addHeader(boost::beast::http::field::location, 14746229577SJames Feist uri + "/Monitor"); 14846229577SJames Feist res.addHeader(boost::beast::http::field::retry_after, 14946229577SJames Feist std::to_string(retryAfterSeconds)); 15046229577SJames Feist } 15146229577SJames Feist else if (!gave204) 15246229577SJames Feist { 15346229577SJames Feist res.result(boost::beast::http::status::no_content); 15446229577SJames Feist gave204 = true; 15546229577SJames Feist } 15646229577SJames Feist } 15746229577SJames Feist 158d609fd6eSEd Tanous void finishTask() 15946229577SJames Feist { 16046229577SJames Feist endTime = std::chrono::system_clock::to_time_t( 16146229577SJames Feist std::chrono::system_clock::now()); 16246229577SJames Feist } 16346229577SJames Feist 164fd9ab9e1SJames Feist void extendTimer(const std::chrono::seconds& timeout) 16546229577SJames Feist { 16646229577SJames Feist timer.expires_after(timeout); 16746229577SJames Feist timer.async_wait( 16846229577SJames Feist [self = shared_from_this()](boost::system::error_code ec) { 16946229577SJames Feist if (ec == boost::asio::error::operation_aborted) 17046229577SJames Feist { 1714e0453b1SGunnar Mills return; // completed successfully 17246229577SJames Feist } 17346229577SJames Feist if (!ec) 17446229577SJames Feist { 17546229577SJames Feist // change ec to error as timer expired 17646229577SJames Feist ec = boost::asio::error::operation_aborted; 17746229577SJames Feist } 17846229577SJames Feist self->match.reset(); 17946229577SJames Feist sdbusplus::message::message msg; 18046229577SJames Feist self->finishTask(); 18146229577SJames Feist self->state = "Cancelled"; 18246229577SJames Feist self->status = "Warning"; 183e5d5006bSJames Feist self->messages.emplace_back( 184e5d5006bSJames Feist messages::taskAborted(std::to_string(self->index))); 185e7686576SSunitha Harish // Send event :TaskAborted 186e7686576SSunitha Harish self->sendTaskEvent(self->state, self->index); 18746229577SJames Feist self->callback(ec, msg, self); 18846229577SJames Feist }); 189fd9ab9e1SJames Feist } 190fd9ab9e1SJames Feist 191e7686576SSunitha Harish void sendTaskEvent(const std::string_view state, size_t index) 192e7686576SSunitha Harish { 193e7686576SSunitha Harish std::string origin = 194e7686576SSunitha Harish "/redfish/v1/TaskService/Tasks/" + std::to_string(index); 195e7686576SSunitha Harish std::string resType = "Task"; 196e7686576SSunitha Harish // TaskState enums which should send out an event are: 197e7686576SSunitha Harish // "Starting" = taskResumed 198e7686576SSunitha Harish // "Running" = taskStarted 199e7686576SSunitha Harish // "Suspended" = taskPaused 200e7686576SSunitha Harish // "Interrupted" = taskPaused 201e7686576SSunitha Harish // "Pending" = taskPaused 202e7686576SSunitha Harish // "Stopping" = taskAborted 203e7686576SSunitha Harish // "Completed" = taskCompletedOK 204e7686576SSunitha Harish // "Killed" = taskRemoved 205e7686576SSunitha Harish // "Exception" = taskCompletedWarning 206e7686576SSunitha Harish // "Cancelled" = taskCancelled 207e7686576SSunitha Harish if (state == "Starting") 208e7686576SSunitha Harish { 209e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 210e7686576SSunitha Harish redfish::messages::taskResumed(std::to_string(index)), origin, 211e7686576SSunitha Harish resType); 212e7686576SSunitha Harish } 213e7686576SSunitha Harish else if (state == "Running") 214e7686576SSunitha Harish { 215e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 216e7686576SSunitha Harish redfish::messages::taskStarted(std::to_string(index)), origin, 217e7686576SSunitha Harish resType); 218e7686576SSunitha Harish } 219e7686576SSunitha Harish else if ((state == "Suspended") || (state == "Interrupted") || 220e7686576SSunitha Harish (state == "Pending")) 221e7686576SSunitha Harish { 222e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 223e7686576SSunitha Harish redfish::messages::taskPaused(std::to_string(index)), origin, 224e7686576SSunitha Harish resType); 225e7686576SSunitha Harish } 226e7686576SSunitha Harish else if (state == "Stopping") 227e7686576SSunitha Harish { 228e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 229e7686576SSunitha Harish redfish::messages::taskAborted(std::to_string(index)), origin, 230e7686576SSunitha Harish resType); 231e7686576SSunitha Harish } 232e7686576SSunitha Harish else if (state == "Completed") 233e7686576SSunitha Harish { 234e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 235e7686576SSunitha Harish redfish::messages::taskCompletedOK(std::to_string(index)), 236e7686576SSunitha Harish origin, resType); 237e7686576SSunitha Harish } 238e7686576SSunitha Harish else if (state == "Killed") 239e7686576SSunitha Harish { 240e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 241e7686576SSunitha Harish redfish::messages::taskRemoved(std::to_string(index)), origin, 242e7686576SSunitha Harish resType); 243e7686576SSunitha Harish } 244e7686576SSunitha Harish else if (state == "Exception") 245e7686576SSunitha Harish { 246e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 247e7686576SSunitha Harish redfish::messages::taskCompletedWarning(std::to_string(index)), 248e7686576SSunitha Harish origin, resType); 249e7686576SSunitha Harish } 250e7686576SSunitha Harish else if (state == "Cancelled") 251e7686576SSunitha Harish { 252e7686576SSunitha Harish redfish::EventServiceManager::getInstance().sendEvent( 253e7686576SSunitha Harish redfish::messages::taskCancelled(std::to_string(index)), origin, 254e7686576SSunitha Harish resType); 255e7686576SSunitha Harish } 256e7686576SSunitha Harish else 257e7686576SSunitha Harish { 258e7686576SSunitha Harish BMCWEB_LOG_INFO << "sendTaskEvent: No events to send"; 259e7686576SSunitha Harish } 260e7686576SSunitha Harish } 261e7686576SSunitha Harish 262fd9ab9e1SJames Feist void startTimer(const std::chrono::seconds& timeout) 263fd9ab9e1SJames Feist { 264fd9ab9e1SJames Feist if (match) 265fd9ab9e1SJames Feist { 266fd9ab9e1SJames Feist return; 267fd9ab9e1SJames Feist } 268fd9ab9e1SJames Feist match = std::make_unique<sdbusplus::bus::match::match>( 269fd9ab9e1SJames Feist static_cast<sdbusplus::bus::bus&>(*crow::connections::systemBus), 270fd9ab9e1SJames Feist matchStr, 271fd9ab9e1SJames Feist [self = shared_from_this()](sdbusplus::message::message& message) { 272fd9ab9e1SJames Feist boost::system::error_code ec; 273fd9ab9e1SJames Feist 274fd9ab9e1SJames Feist // callback to return True if callback is done, callback needs 275fd9ab9e1SJames Feist // to update status itself if needed 276fd9ab9e1SJames Feist if (self->callback(ec, message, self) == task::completed) 277fd9ab9e1SJames Feist { 278fd9ab9e1SJames Feist self->timer.cancel(); 279fd9ab9e1SJames Feist self->finishTask(); 280fd9ab9e1SJames Feist 281e7686576SSunitha Harish // Send event 282e7686576SSunitha Harish self->sendTaskEvent(self->state, self->index); 283e7686576SSunitha Harish 284fd9ab9e1SJames Feist // reset the match after the callback was successful 285fd9ab9e1SJames Feist boost::asio::post( 286fd9ab9e1SJames Feist crow::connections::systemBus->get_io_context(), 287fd9ab9e1SJames Feist [self] { self->match.reset(); }); 288fd9ab9e1SJames Feist return; 289fd9ab9e1SJames Feist } 290fd9ab9e1SJames Feist }); 291fd9ab9e1SJames Feist 292fd9ab9e1SJames Feist extendTimer(timeout); 293e5d5006bSJames Feist messages.emplace_back(messages::taskStarted(std::to_string(index))); 294e7686576SSunitha Harish // Send event : TaskStarted 295e7686576SSunitha Harish sendTaskEvent(state, index); 29646229577SJames Feist } 29746229577SJames Feist 29846229577SJames Feist std::function<bool(boost::system::error_code, sdbusplus::message::message&, 29946229577SJames Feist const std::shared_ptr<TaskData>&)> 30046229577SJames Feist callback; 30146229577SJames Feist std::string matchStr; 30246229577SJames Feist size_t index; 30346229577SJames Feist time_t startTime; 30446229577SJames Feist std::string status; 30546229577SJames Feist std::string state; 30646229577SJames Feist nlohmann::json messages; 30746229577SJames Feist boost::asio::steady_timer timer; 30846229577SJames Feist std::unique_ptr<sdbusplus::bus::match::match> match; 30946229577SJames Feist std::optional<time_t> endTime; 310fe306728SJames Feist std::optional<Payload> payload; 31146229577SJames Feist bool gave204 = false; 3126868ff50SGeorge Liu int percentComplete = 0; 31346229577SJames Feist }; 31446229577SJames Feist 31546229577SJames Feist } // namespace task 31646229577SJames Feist 3177e860f15SJohn Edward Broadbent inline void requestRoutesTaskMonitor(App& app) 31846229577SJames Feist { 3197e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/<str>/Monitor/") 320ed398213SEd Tanous .privileges(redfish::privileges::getTask) 3217e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3227e860f15SJohn Edward Broadbent [](const crow::Request&, 3237e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3247e860f15SJohn Edward Broadbent const std::string& strParam) { 32546229577SJames Feist auto find = std::find_if( 32646229577SJames Feist task::tasks.begin(), task::tasks.end(), 32746229577SJames Feist [&strParam](const std::shared_ptr<task::TaskData>& task) { 32846229577SJames Feist if (!task) 32946229577SJames Feist { 33046229577SJames Feist return false; 33146229577SJames Feist } 33246229577SJames Feist 3337e860f15SJohn Edward Broadbent // we compare against the string version as on failure 3347e860f15SJohn Edward Broadbent // strtoul returns 0 33546229577SJames Feist return std::to_string(task->index) == strParam; 33646229577SJames Feist }); 33746229577SJames Feist 33846229577SJames Feist if (find == task::tasks.end()) 33946229577SJames Feist { 3407e860f15SJohn Edward Broadbent messages::resourceNotFound(asyncResp->res, "Monitor", 3417e860f15SJohn Edward Broadbent strParam); 34246229577SJames Feist return; 34346229577SJames Feist } 34446229577SJames Feist std::shared_ptr<task::TaskData>& ptr = *find; 34546229577SJames Feist // monitor expires after 204 34646229577SJames Feist if (ptr->gave204) 34746229577SJames Feist { 3487e860f15SJohn Edward Broadbent messages::resourceNotFound(asyncResp->res, "Monitor", 3497e860f15SJohn Edward Broadbent strParam); 35046229577SJames Feist return; 35146229577SJames Feist } 35246229577SJames Feist ptr->populateResp(asyncResp->res); 3537e860f15SJohn Edward Broadbent }); 35446229577SJames Feist } 35546229577SJames Feist 3567e860f15SJohn Edward Broadbent inline void requestRoutesTask(App& app) 35746229577SJames Feist { 3587e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/<str>/") 359ed398213SEd Tanous .privileges(redfish::privileges::getTask) 3607e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 3617e860f15SJohn Edward Broadbent [](const crow::Request&, 3627e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3637e860f15SJohn Edward Broadbent const std::string& strParam) { 36446229577SJames Feist auto find = std::find_if( 36546229577SJames Feist task::tasks.begin(), task::tasks.end(), 36646229577SJames Feist [&strParam](const std::shared_ptr<task::TaskData>& task) { 36746229577SJames Feist if (!task) 36846229577SJames Feist { 36946229577SJames Feist return false; 37046229577SJames Feist } 37146229577SJames Feist 3727e860f15SJohn Edward Broadbent // we compare against the string version as on failure 3737e860f15SJohn Edward Broadbent // strtoul returns 0 37446229577SJames Feist return std::to_string(task->index) == strParam; 37546229577SJames Feist }); 37646229577SJames Feist 37746229577SJames Feist if (find == task::tasks.end()) 37846229577SJames Feist { 3797e860f15SJohn Edward Broadbent messages::resourceNotFound(asyncResp->res, "Tasks", 3807e860f15SJohn Edward Broadbent strParam); 38146229577SJames Feist return; 38246229577SJames Feist } 38346229577SJames Feist 38446229577SJames Feist std::shared_ptr<task::TaskData>& ptr = *find; 38546229577SJames Feist 38646229577SJames Feist asyncResp->res.jsonValue["@odata.type"] = "#Task.v1_4_3.Task"; 38746229577SJames Feist asyncResp->res.jsonValue["Id"] = strParam; 38846229577SJames Feist asyncResp->res.jsonValue["Name"] = "Task " + strParam; 38946229577SJames Feist asyncResp->res.jsonValue["TaskState"] = ptr->state; 39046229577SJames Feist asyncResp->res.jsonValue["StartTime"] = 391*1d8782e7SNan Zhou crow::utility::getDateTimeStdtime(ptr->startTime); 39246229577SJames Feist if (ptr->endTime) 39346229577SJames Feist { 39446229577SJames Feist asyncResp->res.jsonValue["EndTime"] = 395*1d8782e7SNan Zhou crow::utility::getDateTimeStdtime(*(ptr->endTime)); 39646229577SJames Feist } 39746229577SJames Feist asyncResp->res.jsonValue["TaskStatus"] = ptr->status; 39846229577SJames Feist asyncResp->res.jsonValue["Messages"] = ptr->messages; 39946229577SJames Feist asyncResp->res.jsonValue["@odata.id"] = 40046229577SJames Feist "/redfish/v1/TaskService/Tasks/" + strParam; 40146229577SJames Feist if (!ptr->gave204) 40246229577SJames Feist { 40346229577SJames Feist asyncResp->res.jsonValue["TaskMonitor"] = 4047e860f15SJohn Edward Broadbent "/redfish/v1/TaskService/Tasks/" + strParam + 4057e860f15SJohn Edward Broadbent "/Monitor"; 40646229577SJames Feist } 407fe306728SJames Feist if (ptr->payload) 408fe306728SJames Feist { 4095fb91ba4SEd Tanous const task::Payload& p = *(ptr->payload); 4105fb91ba4SEd Tanous asyncResp->res.jsonValue["Payload"] = { 4115fb91ba4SEd Tanous {"TargetUri", p.targetUri}, 4125fb91ba4SEd Tanous {"HttpOperation", p.httpOperation}, 4135fb91ba4SEd Tanous {"HttpHeaders", p.httpHeaders}, 41471f52d96SEd Tanous {"JsonBody", 4157e860f15SJohn Edward Broadbent p.jsonBody.dump( 4167e860f15SJohn Edward Broadbent 2, ' ', true, 41771f52d96SEd Tanous nlohmann::json::error_handler_t::replace)}}; 418fe306728SJames Feist } 4197e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["PercentComplete"] = 4207e860f15SJohn Edward Broadbent ptr->percentComplete; 4217e860f15SJohn Edward Broadbent }); 42246229577SJames Feist } 42346229577SJames Feist 4247e860f15SJohn Edward Broadbent inline void requestRoutesTaskCollection(App& app) 42546229577SJames Feist { 4267e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/Tasks/") 427ed398213SEd Tanous .privileges(redfish::privileges::getTaskCollection) 4287e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 4297e860f15SJohn Edward Broadbent [](const crow::Request&, 4307e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 43146229577SJames Feist asyncResp->res.jsonValue["@odata.type"] = 43246229577SJames Feist "#TaskCollection.TaskCollection"; 4337e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.id"] = 4347e860f15SJohn Edward Broadbent "/redfish/v1/TaskService/Tasks"; 43546229577SJames Feist asyncResp->res.jsonValue["Name"] = "Task Collection"; 4367e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members@odata.count"] = 4377e860f15SJohn Edward Broadbent task::tasks.size(); 43846229577SJames Feist nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 43946229577SJames Feist members = nlohmann::json::array(); 44046229577SJames Feist 44146229577SJames Feist for (const std::shared_ptr<task::TaskData>& task : task::tasks) 44246229577SJames Feist { 44346229577SJames Feist if (task == nullptr) 44446229577SJames Feist { 44546229577SJames Feist continue; // shouldn't be possible 44646229577SJames Feist } 4477e860f15SJohn Edward Broadbent members.emplace_back(nlohmann::json{ 4487e860f15SJohn Edward Broadbent {"@odata.id", "/redfish/v1/TaskService/Tasks/" + 44946229577SJames Feist std::to_string(task->index)}}); 45046229577SJames Feist } 4517e860f15SJohn Edward Broadbent }); 45246229577SJames Feist } 45346229577SJames Feist 4547e860f15SJohn Edward Broadbent inline void requestRoutesTaskService(App& app) 45546229577SJames Feist { 4567e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/TaskService/") 457ed398213SEd Tanous .privileges(redfish::privileges::getTaskService) 4587e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 4597e860f15SJohn Edward Broadbent [](const crow::Request&, 4607e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 46146229577SJames Feist asyncResp->res.jsonValue["@odata.type"] = 46246229577SJames Feist "#TaskService.v1_1_4.TaskService"; 4637e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["@odata.id"] = 4647e860f15SJohn Edward Broadbent "/redfish/v1/TaskService"; 46546229577SJames Feist asyncResp->res.jsonValue["Name"] = "Task Service"; 46646229577SJames Feist asyncResp->res.jsonValue["Id"] = "TaskService"; 4677e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DateTime"] = 4687c8c4058STejas Patil crow::utility::getDateTimeOffsetNow().first; 4697e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["CompletedTaskOverWritePolicy"] = 4707e860f15SJohn Edward Broadbent "Oldest"; 47146229577SJames Feist 4727e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["LifeCycleEventOnTaskStateChange"] = 4737e860f15SJohn Edward Broadbent true; 47446229577SJames Feist 47546229577SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 47646229577SJames Feist health->populate(); 47746229577SJames Feist asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 47846229577SJames Feist asyncResp->res.jsonValue["ServiceEnabled"] = true; 47946229577SJames Feist asyncResp->res.jsonValue["Tasks"] = { 48046229577SJames Feist {"@odata.id", "/redfish/v1/TaskService/Tasks"}}; 4817e860f15SJohn Edward Broadbent }); 48246229577SJames Feist } 48346229577SJames Feist 48446229577SJames Feist } // namespace redfish 485