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 20 #include <boost/container/flat_map.hpp> 21 #include <variant> 22 23 namespace redfish 24 { 25 26 /** 27 * DBus types primitives for several generic DBus interfaces 28 * TODO(Pawel) consider move this to separate file into boost::dbus 29 */ 30 // Note, this is not a very useful Variant, but because it isn't used to get 31 // values, it should be as simple as possible 32 // TODO(ed) invent a nullvariant type 33 using VariantType = std::variant<bool, std::string, uint64_t>; 34 using ManagedObjectsType = std::vector<std::pair< 35 sdbusplus::message::object_path, 36 std::vector<std::pair<std::string, 37 std::vector<std::pair<std::string, VariantType>>>>>>; 38 39 using PropertiesType = boost::container::flat_map<std::string, VariantType>; 40 41 /** 42 * ChassisCollection derived class for delivering Chassis Collection Schema 43 */ 44 class ChassisCollection : public Node 45 { 46 public: 47 ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") 48 { 49 entityPrivileges = { 50 {boost::beast::http::verb::get, {{"Login"}}}, 51 {boost::beast::http::verb::head, {{"Login"}}}, 52 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 53 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 54 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 55 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 56 } 57 58 private: 59 /** 60 * Functions triggers appropriate requests on DBus 61 */ 62 void doGet(crow::Response &res, const crow::Request &req, 63 const std::vector<std::string> ¶ms) override 64 { 65 const std::array<const char *, 3> interfaces = { 66 "xyz.openbmc_project.Inventory.Item.Board", 67 "xyz.openbmc_project.Inventory.Item.Chassis", 68 "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 69 res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection"; 70 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 71 res.jsonValue["@odata.context"] = 72 "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"; 73 res.jsonValue["Name"] = "Chassis Collection"; 74 75 auto asyncResp = std::make_shared<AsyncResp>(res); 76 crow::connections::systemBus->async_method_call( 77 [asyncResp](const boost::system::error_code ec, 78 const std::vector<std::string> &chassisList) { 79 if (ec) 80 { 81 messages::internalError(asyncResp->res); 82 return; 83 } 84 nlohmann::json &chassisArray = 85 asyncResp->res.jsonValue["Members"]; 86 chassisArray = nlohmann::json::array(); 87 for (const std::string &objpath : chassisList) 88 { 89 std::size_t lastPos = objpath.rfind("/"); 90 if (lastPos == std::string::npos) 91 { 92 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; 93 continue; 94 } 95 chassisArray.push_back( 96 {{"@odata.id", "/redfish/v1/Chassis/" + 97 objpath.substr(lastPos + 1)}}); 98 } 99 100 asyncResp->res.jsonValue["Members@odata.count"] = 101 chassisArray.size(); 102 }, 103 "xyz.openbmc_project.ObjectMapper", 104 "/xyz/openbmc_project/object_mapper", 105 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 106 "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 107 } 108 }; 109 110 /** 111 * Chassis override class for delivering Chassis Schema 112 */ 113 class Chassis : public Node 114 { 115 public: 116 Chassis(CrowApp &app) : 117 Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 118 { 119 entityPrivileges = { 120 {boost::beast::http::verb::get, {{"Login"}}}, 121 {boost::beast::http::verb::head, {{"Login"}}}, 122 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 123 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 124 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 125 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 126 } 127 128 private: 129 /** 130 * Functions triggers appropriate requests on DBus 131 */ 132 void doGet(crow::Response &res, const crow::Request &req, 133 const std::vector<std::string> ¶ms) override 134 { 135 const std::array<const char *, 3> interfaces = { 136 "xyz.openbmc_project.Inventory.Item.Board", 137 "xyz.openbmc_project.Inventory.Item.Chassis", 138 "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 139 140 // Check if there is required param, truly entering this shall be 141 // impossible. 142 if (params.size() != 1) 143 { 144 messages::internalError(res); 145 res.end(); 146 return; 147 } 148 149 res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 150 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 151 res.jsonValue["@odata.context"] = 152 "/redfish/v1/$metadata#Chassis.Chassis"; 153 res.jsonValue["Name"] = "Chassis Collection"; 154 res.jsonValue["ChassisType"] = "RackMount"; 155 res.jsonValue["PowerState"] = "On"; 156 157 const std::string &chassisId = params[0]; 158 auto asyncResp = std::make_shared<AsyncResp>(res); 159 crow::connections::systemBus->async_method_call( 160 [asyncResp, chassisId(std::string(chassisId))]( 161 const boost::system::error_code ec, 162 const std::vector<std::pair< 163 std::string, std::vector<std::pair< 164 std::string, std::vector<std::string>>>>> 165 &subtree) { 166 if (ec) 167 { 168 messages::internalError(asyncResp->res); 169 return; 170 } 171 // Iterate over all retrieved ObjectPaths. 172 for (const std::pair< 173 std::string, 174 std::vector< 175 std::pair<std::string, std::vector<std::string>>>> 176 &object : subtree) 177 { 178 const std::string &path = object.first; 179 const std::vector< 180 std::pair<std::string, std::vector<std::string>>> 181 &connectionNames = object.second; 182 183 if (!boost::ends_with(path, chassisId)) 184 { 185 continue; 186 } 187 if (connectionNames.size() < 1) 188 { 189 BMCWEB_LOG_ERROR << "Only got " 190 << connectionNames.size() 191 << " Connection names"; 192 continue; 193 } 194 195 const std::string connectionName = connectionNames[0].first; 196 crow::connections::systemBus->async_method_call( 197 [asyncResp, chassisId(std::string(chassisId))]( 198 const boost::system::error_code ec, 199 const std::vector<std::pair< 200 std::string, VariantType>> &propertiesList) { 201 for (const std::pair<std::string, VariantType> 202 &property : propertiesList) 203 { 204 const std::string *value = 205 std::get_if<std::string>(&property.second); 206 if (value != nullptr) 207 { 208 asyncResp->res.jsonValue[property.first] = 209 *value; 210 } 211 } 212 asyncResp->res.jsonValue["Name"] = chassisId; 213 asyncResp->res.jsonValue["Id"] = chassisId; 214 asyncResp->res.jsonValue["Thermal"] = { 215 {"@odata.id", "/redfish/v1/Chassis/" + 216 chassisId + "/Thermal"}}; 217 // Power object 218 asyncResp->res.jsonValue["Power"] = { 219 {"@odata.id", "/redfish/v1/Chassis/" + 220 chassisId + "/Power"}}; 221 asyncResp->res.jsonValue["Status"] = { 222 {"Health", "OK"}, 223 {"State", "Enabled"}, 224 }; 225 226 asyncResp->res 227 .jsonValue["Links"]["ComputerSystems"] = { 228 {{"@odata.id", "/redfish/v1/Systems/system"}}}; 229 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 230 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 231 }, 232 connectionName, path, "org.freedesktop.DBus.Properties", 233 "GetAll", 234 "xyz.openbmc_project.Inventory.Decorator.Asset"); 235 return; 236 } 237 238 // Couldn't find an object with that name. return an error 239 messages::resourceNotFound( 240 asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId); 241 }, 242 "xyz.openbmc_project.ObjectMapper", 243 "/xyz/openbmc_project/object_mapper", 244 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 245 "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 246 } 247 }; 248 } // namespace redfish 249