1 /* 2 // Copyright (c) 2019 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 namespace redfish 21 { 22 class StorageCollection : public Node 23 { 24 public: 25 StorageCollection(CrowApp &app) : 26 Node(app, "/redfish/v1/Systems/system/Storage/") 27 { 28 entityPrivileges = { 29 {boost::beast::http::verb::get, {{"Login"}}}, 30 {boost::beast::http::verb::head, {{"Login"}}}, 31 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 32 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 33 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 34 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 35 } 36 37 private: 38 void doGet(crow::Response &res, const crow::Request &req, 39 const std::vector<std::string> ¶ms) override 40 { 41 res.jsonValue["@odata.type"] = "#StorageCollection.StorageCollection"; 42 res.jsonValue["@odata.context"] = 43 "/redfish/v1/$metadata#StorageCollection.StorageCollection"; 44 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage"; 45 res.jsonValue["Name"] = "Storage Collection"; 46 res.jsonValue["Members"] = { 47 {"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}; 48 res.jsonValue["Members@odata.count"] = 1; 49 } 50 }; 51 52 class Storage : public Node 53 { 54 public: 55 Storage(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/Storage/1") 56 { 57 entityPrivileges = { 58 {boost::beast::http::verb::get, {{"Login"}}}, 59 {boost::beast::http::verb::head, {{"Login"}}}, 60 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 61 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 62 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 63 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 64 } 65 66 private: 67 void doGet(crow::Response &res, const crow::Request &req, 68 const std::vector<std::string> ¶ms) override 69 { 70 res.jsonValue["@odata.type"] = "#Storage.v1_2_0.Storage"; 71 res.jsonValue["@odata.context"] = 72 "/redfish/v1/$metadata#Storage.Storage"; 73 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1"; 74 res.jsonValue["Name"] = "Storage Controller"; 75 res.jsonValue["Id"] = "NVMe Controller"; 76 77 auto asyncResp = std::make_shared<AsyncResp>(res); 78 crow::connections::systemBus->async_method_call( 79 [asyncResp](const boost::system::error_code ec, 80 const std::vector<std::string> &storageList) { 81 nlohmann::json &storageArray = 82 asyncResp->res.jsonValue["Drives"]; 83 storageArray = nlohmann::json::array(); 84 asyncResp->res.jsonValue["Drives@odata.count"] = 0; 85 if (ec) 86 { 87 return; 88 } 89 for (const std::string &objpath : storageList) 90 { 91 std::size_t lastPos = objpath.rfind("/"); 92 if (lastPos == std::string::npos || 93 objpath.size() <= lastPos + 1) 94 { 95 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; 96 continue; 97 } 98 99 storageArray.push_back( 100 {{"@odata.id", 101 "/redfish/v1/Systems/system/Storage/1/Drive/" + 102 objpath.substr(lastPos + 1)}}); 103 } 104 105 asyncResp->res.jsonValue["Drives@odata.count"] = 106 storageArray.size(); 107 }, 108 "xyz.openbmc_project.ObjectMapper", 109 "/xyz/openbmc_project/object_mapper", 110 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 111 "/xyz/openbmc_project/inventory", int32_t(0), 112 std::array<const char *, 1>{ 113 "xyz.openbmc_project.Inventory.Item.Drive"}); 114 } 115 }; 116 117 class Drive : public Node 118 { 119 public: 120 Drive(CrowApp &app) : 121 Node(app, "/redfish/v1/Systems/system/Storage/1/Drive/<str>/", 122 std::string()) 123 { 124 entityPrivileges = { 125 {boost::beast::http::verb::get, {{"Login"}}}, 126 {boost::beast::http::verb::head, {{"Login"}}}, 127 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 128 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 129 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 130 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 131 } 132 133 private: 134 void doGet(crow::Response &res, const crow::Request &req, 135 const std::vector<std::string> ¶ms) override 136 { 137 const std::string &driveId = params[0]; 138 139 auto asyncResp = std::make_shared<AsyncResp>(res); 140 141 crow::connections::systemBus->async_method_call( 142 [asyncResp, driveId]( 143 const boost::system::error_code ec, 144 const std::vector<std::pair< 145 std::string, std::vector<std::pair< 146 std::string, std::vector<std::string>>>>> 147 &subtree) { 148 if (ec) 149 { 150 messages::resourceNotFound(asyncResp->res, "Drive", 151 driveId); 152 return; 153 } 154 155 for (const std::pair< 156 std::string, 157 std::vector< 158 std::pair<std::string, std::vector<std::string>>>> 159 &object : subtree) 160 { 161 const std::string &path = object.first; 162 const std::vector< 163 std::pair<std::string, std::vector<std::string>>> 164 &connectionNames = object.second; 165 166 if (!boost::ends_with(path, "/" + driveId)) 167 { 168 continue; 169 } 170 171 asyncResp->res.jsonValue["@odata.type"] = 172 "#Drive.v1_2_0.Drive"; 173 asyncResp->res.jsonValue["@odata.context"] = 174 "/redfish/v1/$metadata#Drive.Drive"; 175 asyncResp->res.jsonValue["@odata.id"] = 176 "/redfish/v1/Systems/system/Storage/1/Drive/" + driveId; 177 178 if (connectionNames.size() != 1) 179 { 180 BMCWEB_LOG_ERROR << "Connection size " 181 << connectionNames.size() 182 << ", greater than 1"; 183 continue; 184 } 185 186 const std::string &connectionName = 187 connectionNames[0].first; 188 crow::connections::systemBus->async_method_call( 189 [asyncResp, driveId]( 190 const boost::system::error_code ec, 191 const std::vector<std::pair< 192 std::string, 193 std::variant<bool, std::string, uint64_t>>> 194 &propertiesList) { 195 for (const std::pair< 196 std::string, 197 std::variant<bool, std::string, uint64_t>> 198 &property : propertiesList) 199 { 200 // Store DBus properties that are also 201 // Redfish properties with same name and a 202 // string value 203 const std::string &propertyName = 204 property.first; 205 if ((propertyName == "PartNumber") || 206 (propertyName == "SerialNumber") || 207 (propertyName == "Manufacturer") || 208 (propertyName == "Model")) 209 { 210 const std::string *value = 211 std::get_if<std::string>( 212 &property.second); 213 if (value != nullptr) 214 { 215 asyncResp->res.jsonValue[propertyName] = 216 *value; 217 } 218 } 219 } 220 asyncResp->res.jsonValue["Name"] = driveId; 221 asyncResp->res.jsonValue["Id"] = driveId; 222 223 getMainChassisId( 224 asyncResp, [](const std::string &chassisId, 225 std::shared_ptr<AsyncResp> aRsp) { 226 aRsp->res.jsonValue["Links"]["Chassis"] = { 227 {"@odata.id", 228 "/redfish/v1/Chassis/" + chassisId}}; 229 }); 230 }, 231 connectionName, path, "org.freedesktop.DBus.Properties", 232 "GetAll", 233 "xyz.openbmc_project.Inventory.Decorator.Asset"); 234 235 return; 236 } 237 238 // no object found with that name 239 messages::resourceNotFound(asyncResp->res, "Drive", driveId); 240 return; 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), 246 std::array<const char *, 1>{ 247 "xyz.openbmc_project.Inventory.Item.Drive"}); 248 } 249 }; 250 } // namespace redfish