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_data(CallbackFunc &&callback) { 27 crow::connections::system_bus->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 35 std::vector<boost::container::flat_map<std::string, std::string>> 36 output; 37 38 if (error_code) { 39 // Something wrong on DBus, the error_code is not important at this 40 // moment, just return success=false, and empty output. Since size 41 // of vector may vary depending on information from Entity Manager, 42 // and empty output could not be treated same way as error. 43 callback(false, output); 44 return; 45 } 46 47 for (auto &obj : subtree) { 48 const std::vector<std::pair<std::string, std::vector<std::string>>> 49 &connectionNames = obj.second; 50 51 const std::string connectionName = connectionNames[0].first; 52 53 crow::connections::system_bus->async_method_call( 54 [&](const boost::system::error_code error_code, 55 const std::vector<std::pair<std::string, VariantType>> 56 &propertiesList) { 57 for (auto &property : propertiesList) { 58 boost::container::flat_map<std::string, std::string> 59 single_sw_item_properties; 60 single_sw_item_properties[property.first] = 61 *(mapbox::get_ptr<const std::string>(property.second)); 62 output.emplace_back(single_sw_item_properties); 63 } 64 }, 65 connectionName, obj.first, "org.freedesktop.DBus.Properties", 66 "GetAll", "xyz.openbmc_project.Software.Version"); 67 // Finally make a callback with usefull data 68 callback(true, output); 69 } 70 }, 71 "xyz.openbmc_project.ObjectMapper", 72 "/xyz/openbmc_project/object_mapper", 73 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 74 "/xyz/openbmc_project/software", int32_t(0), 75 std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"}); 76 } 77 /* 78 * Function that retrieves all SoftwareInventory available through 79 * Software.BMC.Updater. 80 * @param callback a function that shall be called to convert Dbus output into 81 * JSON. 82 */ 83 template <typename CallbackFunc> 84 void get_software_inventory_list(CallbackFunc &&callback) { 85 get_all_software_inventory_data( 86 [callback]( 87 const bool &success, 88 const std::vector< 89 boost::container::flat_map<std::string, std::string>> &output) { 90 std::vector<std::string> sw_inv_list; 91 for (auto &i : output) { 92 boost::container::flat_map<std::string, std::string>::const_iterator 93 p = i.find("Purpose"); 94 if ((p != i.end())) { 95 const std::string &sw_inv_purpose = 96 boost::get<std::string>(p->second); 97 std::size_t last_pos = sw_inv_purpose.rfind("."); 98 if (last_pos != std::string::npos) { 99 // and put it into output vector. 100 sw_inv_list.emplace_back(sw_inv_purpose.substr(last_pos + 1)); 101 } 102 } 103 } 104 callback(true, sw_inv_list); 105 }); 106 }; 107 108 template <typename CallbackFunc> 109 void get_software_inventory_data(const std::string &res_name, 110 CallbackFunc &&callback) { 111 get_all_software_inventory_data( 112 [res_name, callback]( 113 const bool &success, 114 const std::vector< 115 boost::container::flat_map<std::string, std::string>> &output) { 116 for (auto &i : output) { 117 boost::container::flat_map<std::string, std::string>::const_iterator 118 p = i.find("Purpose"); 119 // Find the one with Purpose matching res_name 120 if ((p != i.end()) && 121 boost::ends_with(boost::get<std::string>(p->second), 122 "." + res_name)) { 123 callback(true, i); 124 } 125 } 126 }); 127 } 128 }; 129 130 class UpdateService : public Node { 131 public: 132 UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") { 133 Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; 134 Node::json["@odata.id"] = "/redfish/v1/UpdateService"; 135 Node::json["@odata.context"] = 136 "/redfish/v1/$metadata#UpdateService.UpdateService"; 137 Node::json["Id"] = "UpdateService"; 138 Node::json["Description"] = "Service for Software Update"; 139 Node::json["Name"] = "Update Service"; 140 Node::json["ServiceEnabled"] = true; // UpdateService cannot be disabled 141 Node::json["SoftwareInventory"] = { 142 {"@odata.id", "/redfish/v1/UpdateService/SoftwareInventory"}}; 143 144 entityPrivileges = { 145 {boost::beast::http::verb::get, {{"Login"}}}, 146 {boost::beast::http::verb::head, {{"Login"}}}, 147 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 148 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 149 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 150 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 151 } 152 153 private: 154 void doGet(crow::response &res, const crow::request &req, 155 const std::vector<std::string> ¶ms) override { 156 res.json_value = Node::json; 157 res.end(); 158 } 159 }; 160 161 class SoftwareInventoryCollection : public Node { 162 public: 163 /* 164 * Default Constructor 165 */ 166 template <typename CrowApp> 167 SoftwareInventoryCollection(CrowApp &app) 168 : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/") { 169 Node::json["@odata.type"] = 170 "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 171 Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory"; 172 Node::json["@odata.context"] = 173 "/redfish/v1/" 174 "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 175 Node::json["Name"] = "Software Inventory Collection"; 176 177 entityPrivileges = { 178 {boost::beast::http::verb::get, {{"Login"}}}, 179 {boost::beast::http::verb::head, {{"Login"}}}, 180 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 181 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 182 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 183 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 184 } 185 186 private: 187 /** 188 * Functions triggers appropriate requests on DBus 189 */ 190 void doGet(crow::response &res, const crow::request &req, 191 const std::vector<std::string> ¶ms) override { 192 res.json_value = Node::json; 193 // Get sw inventory list, and call the below callback for JSON preparation 194 software_inventory_provider.get_software_inventory_list( 195 [&](const bool &success, const std::vector<std::string> &output) { 196 197 if (success) { 198 // ... prepare json array with appropriate @odata.id links 199 nlohmann::json sw_inventory_array = nlohmann::json::array(); 200 for (const std::string &sw_item : output) { 201 sw_inventory_array.push_back( 202 {{"@odata.id", 203 "/redfish/v1/UpdateService/SoftwareInventory/" + sw_item}}); 204 } 205 // Then attach members, count size and return 206 207 Node::json["Members"] = sw_inventory_array; 208 Node::json["Members@odata.count"] = sw_inventory_array.size(); 209 res.json_value = Node::json; 210 } else { 211 // ... otherwise, return INTERNALL ERROR 212 res.result(boost::beast::http::status::internal_server_error); 213 } 214 res.end(); 215 }); 216 res.end(); 217 } 218 OnDemandSoftwareInventoryProvider software_inventory_provider; 219 }; 220 /** 221 * Chassis override class for delivering Chassis Schema 222 */ 223 class SoftwareInventory : public Node { 224 public: 225 /* 226 * Default Constructor 227 */ 228 template <typename CrowApp> 229 SoftwareInventory(CrowApp &app) 230 : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/<str>/", 231 std::string()) { 232 Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory"; 233 Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory"; 234 Node::json["@odata.context"] = 235 "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 236 Node::json["Name"] = "Software Inventory"; 237 Node::json["Status"] = "OK"; // TODO 238 Node::json["Updateable"] = "No"; 239 240 entityPrivileges = { 241 {boost::beast::http::verb::get, {{"Login"}}}, 242 {boost::beast::http::verb::head, {{"Login"}}}, 243 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 244 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 245 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 246 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 247 } 248 249 private: 250 /** 251 * Functions triggers appropriate requests on DBus 252 */ 253 void doGet(crow::response &res, const crow::request &req, 254 const std::vector<std::string> ¶ms) override { 255 if (params.size() != 1) { 256 res.result(boost::beast::http::status::internal_server_error); 257 res.end(); 258 return; 259 } 260 const std::string &sw_id = params[0]; 261 software_inventory_provider.get_software_inventory_data( 262 sw_id, [&, id{std::string(sw_id)} ]( 263 const bool &success, 264 const boost::container::flat_map<std::string, std::string> 265 &output) { 266 res.json_value = Node::json; 267 // If success... 268 if (success) { 269 // prepare all the schema required fields. 270 res.json_value["@odata.id"] = 271 "/redfish/v1/UpdateService/SoftwareInventory/" + id; 272 // also the one from dbus 273 boost::container::flat_map<std::string, std::string>::const_iterator 274 it = output.find("Version"); 275 res.json_value["Version"] = boost::get<std::string>(it->second); 276 277 res.json_value["Id"] = id; 278 // prepare respond, and send 279 } else { 280 res.result(boost::beast::http::status::not_found); 281 } 282 res.end(); 283 }); 284 } 285 286 OnDemandSoftwareInventoryProvider software_inventory_provider; 287 }; 288 289 } // namespace redfish 290