1a25aeccfSNikhil Potade /* 2a25aeccfSNikhil Potade // Copyright (c) 2019 Intel Corporation 3a25aeccfSNikhil Potade // 4a25aeccfSNikhil Potade // Licensed under the Apache License, Version 2.0 (the "License"); 5a25aeccfSNikhil Potade // you may not use this file except in compliance with the License. 6a25aeccfSNikhil Potade // You may obtain a copy of the License at 7a25aeccfSNikhil Potade // 8a25aeccfSNikhil Potade // http://www.apache.org/licenses/LICENSE-2.0 9a25aeccfSNikhil Potade // 10a25aeccfSNikhil Potade // Unless required by applicable law or agreed to in writing, software 11a25aeccfSNikhil Potade // distributed under the License is distributed on an "AS IS" BASIS, 12a25aeccfSNikhil Potade // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a25aeccfSNikhil Potade // See the License for the specific language governing permissions and 14a25aeccfSNikhil Potade // limitations under the License. 15a25aeccfSNikhil Potade */ 16a25aeccfSNikhil Potade #pragma once 17a25aeccfSNikhil Potade 18a25aeccfSNikhil Potade #include <node.hpp> 19a25aeccfSNikhil Potade 20a25aeccfSNikhil Potade namespace redfish 21a25aeccfSNikhil Potade { 22a25aeccfSNikhil Potade class StorageCollection : public Node 23a25aeccfSNikhil Potade { 24a25aeccfSNikhil Potade public: 25a25aeccfSNikhil Potade StorageCollection(CrowApp &app) : 26a25aeccfSNikhil Potade Node(app, "/redfish/v1/Systems/system/Storage/") 27a25aeccfSNikhil Potade { 28a25aeccfSNikhil Potade entityPrivileges = { 29a25aeccfSNikhil Potade {boost::beast::http::verb::get, {{"Login"}}}, 30a25aeccfSNikhil Potade {boost::beast::http::verb::head, {{"Login"}}}, 31a25aeccfSNikhil Potade {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 32a25aeccfSNikhil Potade {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 33a25aeccfSNikhil Potade {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 34a25aeccfSNikhil Potade {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 35a25aeccfSNikhil Potade } 36a25aeccfSNikhil Potade 37a25aeccfSNikhil Potade private: 38a25aeccfSNikhil Potade void doGet(crow::Response &res, const crow::Request &req, 39a25aeccfSNikhil Potade const std::vector<std::string> ¶ms) override 40a25aeccfSNikhil Potade { 41a25aeccfSNikhil Potade res.jsonValue["@odata.type"] = "#StorageCollection.StorageCollection"; 42a25aeccfSNikhil Potade res.jsonValue["@odata.context"] = 43a25aeccfSNikhil Potade "/redfish/v1/$metadata#StorageCollection.StorageCollection"; 44a25aeccfSNikhil Potade res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage"; 45a25aeccfSNikhil Potade res.jsonValue["Name"] = "Storage Collection"; 46a25aeccfSNikhil Potade res.jsonValue["Members"] = { 47a25aeccfSNikhil Potade {{"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}}; 48a25aeccfSNikhil Potade res.jsonValue["Members@odata.count"] = 1; 49a25aeccfSNikhil Potade res.end(); 50a25aeccfSNikhil Potade } 51a25aeccfSNikhil Potade }; 52a25aeccfSNikhil Potade 53a25aeccfSNikhil Potade class Storage : public Node 54a25aeccfSNikhil Potade { 55a25aeccfSNikhil Potade public: 56a25aeccfSNikhil Potade Storage(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/Storage/1") 57a25aeccfSNikhil Potade { 58a25aeccfSNikhil Potade entityPrivileges = { 59a25aeccfSNikhil Potade {boost::beast::http::verb::get, {{"Login"}}}, 60a25aeccfSNikhil Potade {boost::beast::http::verb::head, {{"Login"}}}, 61a25aeccfSNikhil Potade {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 62a25aeccfSNikhil Potade {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 63a25aeccfSNikhil Potade {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 64a25aeccfSNikhil Potade {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 65a25aeccfSNikhil Potade } 66a25aeccfSNikhil Potade 67a25aeccfSNikhil Potade private: 68a25aeccfSNikhil Potade void doGet(crow::Response &res, const crow::Request &req, 69a25aeccfSNikhil Potade const std::vector<std::string> ¶ms) override 70a25aeccfSNikhil Potade { 71a25aeccfSNikhil Potade res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage"; 72a25aeccfSNikhil Potade res.jsonValue["@odata.context"] = 73a25aeccfSNikhil Potade "/redfish/v1/$metadata#Storage.Storage"; 74a25aeccfSNikhil Potade res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1"; 75a25aeccfSNikhil Potade res.jsonValue["Name"] = "Storage Controller"; 76a25aeccfSNikhil Potade res.jsonValue["Id"] = "1"; 77a25aeccfSNikhil Potade 78a25aeccfSNikhil Potade auto asyncResp = std::make_shared<AsyncResp>(res); 79a25aeccfSNikhil Potade crow::connections::systemBus->async_method_call( 80a25aeccfSNikhil Potade [asyncResp](const boost::system::error_code ec, 81a25aeccfSNikhil Potade const std::vector<std::string> &storageList) { 82a25aeccfSNikhil Potade nlohmann::json &storageArray = 83a25aeccfSNikhil Potade asyncResp->res.jsonValue["Drives"]; 84a25aeccfSNikhil Potade storageArray = nlohmann::json::array(); 85a25aeccfSNikhil Potade asyncResp->res.jsonValue["Drives@odata.count"] = 0; 86a25aeccfSNikhil Potade if (ec) 87a25aeccfSNikhil Potade { 88a25aeccfSNikhil Potade BMCWEB_LOG_ERROR << "Drive mapper call error"; 89a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 90a25aeccfSNikhil Potade return; 91a25aeccfSNikhil Potade } 92a25aeccfSNikhil Potade for (const std::string &objpath : storageList) 93a25aeccfSNikhil Potade { 94a25aeccfSNikhil Potade std::size_t lastPos = objpath.rfind("/"); 95a25aeccfSNikhil Potade if (lastPos == std::string::npos || 96a25aeccfSNikhil Potade (objpath.size() <= lastPos + 1)) 97a25aeccfSNikhil Potade { 98a25aeccfSNikhil Potade BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; 99a25aeccfSNikhil Potade continue; 100a25aeccfSNikhil Potade } 101a25aeccfSNikhil Potade 102a25aeccfSNikhil Potade storageArray.push_back( 103a25aeccfSNikhil Potade {{"@odata.id", 104*be13ceceSJames Feist "/redfish/v1/Systems/system/Storage/1/Drives/" + 105a25aeccfSNikhil Potade objpath.substr(lastPos + 1)}}); 106a25aeccfSNikhil Potade } 107a25aeccfSNikhil Potade 108a25aeccfSNikhil Potade asyncResp->res.jsonValue["Drives@odata.count"] = 109a25aeccfSNikhil Potade storageArray.size(); 110a25aeccfSNikhil Potade }, 111a25aeccfSNikhil Potade "xyz.openbmc_project.ObjectMapper", 112a25aeccfSNikhil Potade "/xyz/openbmc_project/object_mapper", 113a25aeccfSNikhil Potade "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 114a25aeccfSNikhil Potade "/xyz/openbmc_project/inventory", int32_t(0), 115a25aeccfSNikhil Potade std::array<const char *, 1>{ 116a25aeccfSNikhil Potade "xyz.openbmc_project.Inventory.Item.Drive"}); 117a25aeccfSNikhil Potade } 118a25aeccfSNikhil Potade }; 119a25aeccfSNikhil Potade 120a25aeccfSNikhil Potade class Drive : public Node 121a25aeccfSNikhil Potade { 122a25aeccfSNikhil Potade public: 123a25aeccfSNikhil Potade Drive(CrowApp &app) : 124*be13ceceSJames Feist Node(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/", 125a25aeccfSNikhil Potade std::string()) 126a25aeccfSNikhil Potade { 127a25aeccfSNikhil Potade entityPrivileges = { 128a25aeccfSNikhil Potade {boost::beast::http::verb::get, {{"Login"}}}, 129a25aeccfSNikhil Potade {boost::beast::http::verb::head, {{"Login"}}}, 130a25aeccfSNikhil Potade {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 131a25aeccfSNikhil Potade {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 132a25aeccfSNikhil Potade {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 133a25aeccfSNikhil Potade {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 134a25aeccfSNikhil Potade } 135a25aeccfSNikhil Potade 136a25aeccfSNikhil Potade private: 137a25aeccfSNikhil Potade void doGet(crow::Response &res, const crow::Request &req, 138a25aeccfSNikhil Potade const std::vector<std::string> ¶ms) override 139a25aeccfSNikhil Potade { 140a25aeccfSNikhil Potade const std::string &driveId = params[0]; 141a25aeccfSNikhil Potade 142a25aeccfSNikhil Potade auto asyncResp = std::make_shared<AsyncResp>(res); 143a25aeccfSNikhil Potade 144a25aeccfSNikhil Potade crow::connections::systemBus->async_method_call( 145a25aeccfSNikhil Potade [asyncResp, driveId]( 146a25aeccfSNikhil Potade const boost::system::error_code ec, 147a25aeccfSNikhil Potade const std::vector<std::pair< 148a25aeccfSNikhil Potade std::string, std::vector<std::pair< 149a25aeccfSNikhil Potade std::string, std::vector<std::string>>>>> 150a25aeccfSNikhil Potade &subtree) { 151a25aeccfSNikhil Potade if (ec) 152a25aeccfSNikhil Potade { 153a25aeccfSNikhil Potade BMCWEB_LOG_ERROR << "Drive mapper call error"; 154a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 155a25aeccfSNikhil Potade return; 156a25aeccfSNikhil Potade } 157a25aeccfSNikhil Potade 158a25aeccfSNikhil Potade auto object = std::find_if( 159a25aeccfSNikhil Potade subtree.begin(), subtree.end(), [&driveId](auto &object) { 160a25aeccfSNikhil Potade const std::string &path = object.first; 161a25aeccfSNikhil Potade return boost::ends_with(path, "/" + driveId); 162a25aeccfSNikhil Potade }); 163a25aeccfSNikhil Potade 164a25aeccfSNikhil Potade if (object == subtree.end()) 165a25aeccfSNikhil Potade { 166a25aeccfSNikhil Potade messages::resourceNotFound(asyncResp->res, "Drive", 167a25aeccfSNikhil Potade driveId); 168a25aeccfSNikhil Potade return; 169a25aeccfSNikhil Potade } 170a25aeccfSNikhil Potade 171a25aeccfSNikhil Potade const std::string &path = object->first; 172a25aeccfSNikhil Potade const std::vector< 173a25aeccfSNikhil Potade std::pair<std::string, std::vector<std::string>>> 174a25aeccfSNikhil Potade &connectionNames = object->second; 175a25aeccfSNikhil Potade 176a25aeccfSNikhil Potade asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; 177a25aeccfSNikhil Potade asyncResp->res.jsonValue["@odata.context"] = 178a25aeccfSNikhil Potade "/redfish/v1/$metadata#Drive.Drive"; 179a25aeccfSNikhil Potade asyncResp->res.jsonValue["@odata.id"] = 180*be13ceceSJames Feist "/redfish/v1/Systems/system/Storage/1/Drives/" + driveId; 181a25aeccfSNikhil Potade 182a25aeccfSNikhil Potade if (connectionNames.size() != 1) 183a25aeccfSNikhil Potade { 184a25aeccfSNikhil Potade BMCWEB_LOG_ERROR << "Connection size " 185a25aeccfSNikhil Potade << connectionNames.size() 186a25aeccfSNikhil Potade << ", greater than 1"; 187a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 188a25aeccfSNikhil Potade return; 189a25aeccfSNikhil Potade } 190a25aeccfSNikhil Potade 191a25aeccfSNikhil Potade getMainChassisId( 192a25aeccfSNikhil Potade asyncResp, [](const std::string &chassisId, 193a25aeccfSNikhil Potade std::shared_ptr<AsyncResp> aRsp) { 194a25aeccfSNikhil Potade aRsp->res.jsonValue["Links"]["Chassis"] = { 195a25aeccfSNikhil Potade {"@odata.id", "/redfish/v1/Chassis/" + chassisId}}; 196a25aeccfSNikhil Potade }); 197a25aeccfSNikhil Potade 198a25aeccfSNikhil Potade const std::string &connectionName = connectionNames[0].first; 199a25aeccfSNikhil Potade crow::connections::systemBus->async_method_call( 200a25aeccfSNikhil Potade [asyncResp, 201a25aeccfSNikhil Potade driveId](const boost::system::error_code ec, 202a25aeccfSNikhil Potade const std::vector<std::pair< 203a25aeccfSNikhil Potade std::string, 204a25aeccfSNikhil Potade std::variant<bool, std::string, uint64_t>>> 205a25aeccfSNikhil Potade &propertiesList) { 206a25aeccfSNikhil Potade if (ec) 207a25aeccfSNikhil Potade { 208a25aeccfSNikhil Potade // this interface isn't necessary 209a25aeccfSNikhil Potade return; 210a25aeccfSNikhil Potade } 211a25aeccfSNikhil Potade for (const std::pair<std::string, 212a25aeccfSNikhil Potade std::variant<bool, std::string, 213a25aeccfSNikhil Potade uint64_t>> &property : 214a25aeccfSNikhil Potade propertiesList) 215a25aeccfSNikhil Potade { 216a25aeccfSNikhil Potade // Store DBus properties that are also 217a25aeccfSNikhil Potade // Redfish properties with same name and a 218a25aeccfSNikhil Potade // string value 219a25aeccfSNikhil Potade const std::string &propertyName = property.first; 220a25aeccfSNikhil Potade if ((propertyName == "PartNumber") || 221a25aeccfSNikhil Potade (propertyName == "SerialNumber") || 222a25aeccfSNikhil Potade (propertyName == "Manufacturer") || 223a25aeccfSNikhil Potade (propertyName == "Model")) 224a25aeccfSNikhil Potade { 225a25aeccfSNikhil Potade const std::string *value = 226a25aeccfSNikhil Potade std::get_if<std::string>(&property.second); 227a25aeccfSNikhil Potade if (value == nullptr) 228a25aeccfSNikhil Potade { 229a25aeccfSNikhil Potade // illegal property 230a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 231a25aeccfSNikhil Potade continue; 232a25aeccfSNikhil Potade } 233a25aeccfSNikhil Potade asyncResp->res.jsonValue[propertyName] = *value; 234a25aeccfSNikhil Potade } 235a25aeccfSNikhil Potade } 236a25aeccfSNikhil Potade asyncResp->res.jsonValue["Name"] = driveId; 237a25aeccfSNikhil Potade asyncResp->res.jsonValue["Id"] = driveId; 238a25aeccfSNikhil Potade }, 239a25aeccfSNikhil Potade connectionName, path, "org.freedesktop.DBus.Properties", 240a25aeccfSNikhil Potade "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset"); 241a25aeccfSNikhil Potade 242a25aeccfSNikhil Potade // default it to Enabled 243a25aeccfSNikhil Potade asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 244a25aeccfSNikhil Potade 245a25aeccfSNikhil Potade crow::connections::systemBus->async_method_call( 246a25aeccfSNikhil Potade [asyncResp, path](const boost::system::error_code ec, 247a25aeccfSNikhil Potade const std::variant<bool> present) { 248a25aeccfSNikhil Potade // this interface isn't necessary, only check it if we 249a25aeccfSNikhil Potade // get a good return 250a25aeccfSNikhil Potade if (!ec) 251a25aeccfSNikhil Potade { 252a25aeccfSNikhil Potade const bool *enabled = std::get_if<bool>(&present); 253a25aeccfSNikhil Potade if (enabled == nullptr) 254a25aeccfSNikhil Potade { 255a25aeccfSNikhil Potade BMCWEB_LOG_DEBUG << "Illegal property present"; 256a25aeccfSNikhil Potade messages::internalError(asyncResp->res); 257a25aeccfSNikhil Potade return; 258a25aeccfSNikhil Potade } 259a25aeccfSNikhil Potade if (!(*enabled)) 260a25aeccfSNikhil Potade { 261a25aeccfSNikhil Potade asyncResp->res.jsonValue["Status"]["State"] = 262a25aeccfSNikhil Potade "Disabled"; 263a25aeccfSNikhil Potade return; 264a25aeccfSNikhil Potade } 265a25aeccfSNikhil Potade } 266a25aeccfSNikhil Potade 267a25aeccfSNikhil Potade // only populate if Enabled, assume enabled unless item 268a25aeccfSNikhil Potade // interface says otherwise 269a25aeccfSNikhil Potade auto health = 270a25aeccfSNikhil Potade std::make_shared<HealthPopulate>(asyncResp); 271a25aeccfSNikhil Potade health->inventory = std::vector<std::string>{path}; 272a25aeccfSNikhil Potade 273a25aeccfSNikhil Potade health->populate(); 274a25aeccfSNikhil Potade }, 275a25aeccfSNikhil Potade connectionName, path, "org.freedesktop.DBus.Properties", 276a25aeccfSNikhil Potade "Get", "xyz.openbmc_project.Inventory.Item", "Present"); 27722984074SJames Feist 27822984074SJames Feist crow::connections::systemBus->async_method_call( 27922984074SJames Feist [asyncResp](const boost::system::error_code ec, 28022984074SJames Feist const std::variant<bool> rebuilding) { 28122984074SJames Feist // this interface isn't necessary, only check it if we 28222984074SJames Feist // get a good return 28322984074SJames Feist if (ec) 28422984074SJames Feist { 28522984074SJames Feist return; 28622984074SJames Feist } 28722984074SJames Feist const bool *updating = std::get_if<bool>(&rebuilding); 28822984074SJames Feist if (updating == nullptr) 28922984074SJames Feist { 29022984074SJames Feist BMCWEB_LOG_DEBUG << "Illegal property present"; 29122984074SJames Feist messages::internalError(asyncResp->res); 29222984074SJames Feist return; 29322984074SJames Feist } 29422984074SJames Feist 29522984074SJames Feist // updating and disabled in the backend shouldn't be 29622984074SJames Feist // able to be set at the same time, so we don't need to 29722984074SJames Feist // check for the race condition of these two calls 29822984074SJames Feist if ((*updating)) 29922984074SJames Feist { 30022984074SJames Feist asyncResp->res.jsonValue["Status"]["State"] = 30122984074SJames Feist "Updating"; 30222984074SJames Feist } 30322984074SJames Feist }, 30422984074SJames Feist connectionName, path, "org.freedesktop.DBus.Properties", 30522984074SJames Feist "Get", "xyz.openbmc_project.State.Drive", "Rebuilding"); 306a25aeccfSNikhil Potade }, 307a25aeccfSNikhil Potade "xyz.openbmc_project.ObjectMapper", 308a25aeccfSNikhil Potade "/xyz/openbmc_project/object_mapper", 309a25aeccfSNikhil Potade "xyz.openbmc_project.ObjectMapper", "GetSubTree", 310a25aeccfSNikhil Potade "/xyz/openbmc_project/inventory", int32_t(0), 311a25aeccfSNikhil Potade std::array<const char *, 1>{ 312a25aeccfSNikhil Potade "xyz.openbmc_project.Inventory.Item.Drive"}); 313a25aeccfSNikhil Potade } 314a25aeccfSNikhil Potade }; 315a25aeccfSNikhil Potade } // namespace redfish 316