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