1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include "node.hpp" 19 #include <boost/container/flat_map.hpp> 20 21 namespace redfish { 22 23 class OnDemandSoftwareInventoryProvider { 24 public: 25 template <typename CallbackFunc> 26 void get_all_software_inventory_object(CallbackFunc &&callback) { 27 crow::connections::systemBus->async_method_call( 28 [callback{std::move(callback)}]( 29 const boost::system::error_code error_code, 30 const std::vector<std::pair< 31 std::string, 32 std::vector<std::pair<std::string, std::vector<std::string>>>>> 33 &subtree) { 34 BMCWEB_LOG_DEBUG << "get all software inventory object callback..."; 35 if (error_code) { 36 // Something wrong on DBus, the error_code is not important at this 37 // moment, just return success=false, and empty output. Since size 38 // of vector may vary depending on information from Entity Manager, 39 // and empty output could not be treated same way as error. 40 callback(false, subtree); 41 return; 42 } 43 44 if (subtree.empty()) { 45 BMCWEB_LOG_DEBUG << "subtree empty"; 46 callback(false, subtree); 47 } else { 48 BMCWEB_LOG_DEBUG << "subtree has something"; 49 callback(true, subtree); 50 } 51 }, 52 "xyz.openbmc_project.ObjectMapper", 53 "/xyz/openbmc_project/object_mapper", 54 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 55 "/xyz/openbmc_project/software", int32_t(1), 56 std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"}); 57 } 58 }; 59 60 class UpdateService : public Node { 61 public: 62 UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") { 63 Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; 64 Node::json["@odata.id"] = "/redfish/v1/UpdateService"; 65 Node::json["@odata.context"] = 66 "/redfish/v1/$metadata#UpdateService.UpdateService"; 67 Node::json["Id"] = "UpdateService"; 68 Node::json["Description"] = "Service for Software Update"; 69 Node::json["Name"] = "Update Service"; 70 Node::json["ServiceEnabled"] = true; // UpdateService cannot be disabled 71 Node::json["FirmwareInventory"] = { 72 {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 73 74 entityPrivileges = { 75 {boost::beast::http::verb::get, {{"Login"}}}, 76 {boost::beast::http::verb::head, {{"Login"}}}, 77 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 78 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 79 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 80 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 81 } 82 83 private: 84 void doGet(crow::Response &res, const crow::Request &req, 85 const std::vector<std::string> ¶ms) override { 86 res.jsonValue = Node::json; 87 res.end(); 88 } 89 }; 90 91 class SoftwareInventoryCollection : public Node { 92 public: 93 /* 94 * Default Constructor 95 */ 96 template <typename CrowApp> 97 SoftwareInventoryCollection(CrowApp &app) 98 : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") { 99 Node::json["@odata.type"] = 100 "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 101 Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory"; 102 Node::json["@odata.context"] = 103 "/redfish/v1/" 104 "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 105 Node::json["Name"] = "Software Inventory Collection"; 106 107 entityPrivileges = { 108 {boost::beast::http::verb::get, {{"Login"}}}, 109 {boost::beast::http::verb::head, {{"Login"}}}, 110 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 111 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 112 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 113 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 114 } 115 116 private: 117 /** 118 * Functions triggers appropriate requests on DBus 119 */ 120 void doGet(crow::Response &res, const crow::Request &req, 121 const std::vector<std::string> ¶ms) override { 122 res.jsonValue = Node::json; 123 softwareInventoryProvider.get_all_software_inventory_object( 124 [&](const bool &success, 125 const std::vector<std::pair< 126 std::string, 127 std::vector<std::pair<std::string, std::vector<std::string>>>>> 128 &subtree) { 129 if (!success) { 130 res.result(boost::beast::http::status::internal_server_error); 131 res.end(); 132 return; 133 } 134 135 if (subtree.empty()) { 136 BMCWEB_LOG_DEBUG << "subtree empty!!"; 137 res.end(); 138 return; 139 } 140 141 res.jsonValue["Members"] = nlohmann::json::array(); 142 143 for (auto &obj : subtree) { 144 const std::vector<std::pair<std::string, std::vector<std::string>>> 145 &connections = obj.second; 146 147 for (auto &conn : connections) { 148 const std::string connectionName = conn.first; 149 BMCWEB_LOG_DEBUG << "connectionName = " << connectionName; 150 BMCWEB_LOG_DEBUG << "obj.first = " << obj.first; 151 152 crow::connections::systemBus->async_method_call( 153 [&](const boost::system::error_code error_code, 154 const boost::container::flat_map<std::string, VariantType> 155 &propertiesList) { 156 BMCWEB_LOG_DEBUG << "safe returned in lambda function"; 157 if (error_code) { 158 res.result( 159 boost::beast::http::status::internal_server_error); 160 res.end(); 161 return; 162 } 163 boost::container::flat_map<std::string, 164 VariantType>::const_iterator it = 165 propertiesList.find("Purpose"); 166 const std::string &sw_inv_purpose = 167 *(mapbox::getPtr<const std::string>(it->second)); 168 std::size_t last_pos = sw_inv_purpose.rfind("."); 169 if (last_pos != std::string::npos) { 170 res.jsonValue["Members"].push_back( 171 {{"@odata.id", 172 "/redfish/v1/UpdateService/FirmwareInventory/" + 173 sw_inv_purpose.substr(last_pos + 1)}}); 174 res.jsonValue["Members@odata.count"] = 175 res.jsonValue["Members"].size(); 176 res.end(); 177 } 178 179 }, 180 connectionName, obj.first, "org.freedesktop.DBus.Properties", 181 "GetAll", "xyz.openbmc_project.Software.Version"); 182 } 183 } 184 }); 185 } 186 OnDemandSoftwareInventoryProvider softwareInventoryProvider; 187 }; 188 /** 189 * Chassis override class for delivering Chassis Schema 190 */ 191 class SoftwareInventory : public Node { 192 public: 193 /* 194 * Default Constructor 195 */ 196 template <typename CrowApp> 197 SoftwareInventory(CrowApp &app) 198 : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 199 std::string()) { 200 Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory"; 201 Node::json["@odata.context"] = 202 "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 203 Node::json["Name"] = "Software Inventory"; 204 Node::json["Status"] = "OK"; // TODO 205 Node::json["Updateable"] = false; 206 207 entityPrivileges = { 208 {boost::beast::http::verb::get, {{"Login"}}}, 209 {boost::beast::http::verb::head, {{"Login"}}}, 210 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 211 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 212 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 213 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 214 } 215 216 private: 217 /** 218 * Functions triggers appropriate requests on DBus 219 */ 220 void doGet(crow::Response &res, const crow::Request &req, 221 const std::vector<std::string> ¶ms) override { 222 res.jsonValue = Node::json; 223 224 if (params.size() != 1) { 225 res.result(boost::beast::http::status::internal_server_error); 226 res.end(); 227 return; 228 } 229 230 const std::string &sw_id = params[0]; 231 res.jsonValue["@odata.id"] = 232 "/redfish/v1/UpdateService/FirmwareInventory/" + sw_id; 233 softwareInventoryProvider.get_all_software_inventory_object( 234 [&, id{std::string(sw_id)} ]( 235 const bool &success, 236 const std::vector<std::pair< 237 std::string, 238 std::vector<std::pair<std::string, std::vector<std::string>>>>> 239 &subtree) { 240 BMCWEB_LOG_DEBUG << "doGet callback..."; 241 if (!success) { 242 res.result(boost::beast::http::status::internal_server_error); 243 res.end(); 244 return; 245 } 246 247 if (subtree.empty()) { 248 BMCWEB_LOG_DEBUG << "subtree empty!!"; 249 res.end(); 250 return; 251 } 252 253 for (auto &obj : subtree) { 254 const std::vector<std::pair<std::string, std::vector<std::string>>> 255 &connections = obj.second; 256 257 for (auto &conn : connections) { 258 const std::string connectionName = conn.first; 259 BMCWEB_LOG_DEBUG << "connectionName = " << connectionName; 260 BMCWEB_LOG_DEBUG << "obj.first = " << obj.first; 261 262 crow::connections::systemBus->async_method_call( 263 [&, id{std::string(id)} ]( 264 const boost::system::error_code error_code, 265 const boost::container::flat_map<std::string, VariantType> 266 &propertiesList) { 267 if (error_code) { 268 res.result( 269 boost::beast::http::status::internal_server_error); 270 res.end(); 271 return; 272 } 273 boost::container::flat_map<std::string, 274 VariantType>::const_iterator it = 275 propertiesList.find("Purpose"); 276 if (it == propertiesList.end()) { 277 BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!"; 278 return; 279 } 280 const std::string &sw_inv_purpose = 281 *(mapbox::getPtr<const std::string>(it->second)); 282 BMCWEB_LOG_DEBUG << "sw_inv_purpose = " << sw_inv_purpose; 283 if (boost::ends_with(sw_inv_purpose, "." + id)) { 284 it = propertiesList.find("Version"); 285 if (it == propertiesList.end()) { 286 BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!"; 287 return; 288 } 289 res.jsonValue["Version"] = 290 *(mapbox::getPtr<const std::string>(it->second)); 291 res.jsonValue["Id"] = id; 292 res.end(); 293 } 294 295 }, 296 connectionName, obj.first, "org.freedesktop.DBus.Properties", 297 "GetAll", "xyz.openbmc_project.Software.Version"); 298 } 299 } 300 }); 301 } 302 303 OnDemandSoftwareInventoryProvider softwareInventoryProvider; 304 }; 305 306 } // namespace redfish 307