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