diff options
author | Nikhil Potade <nikhil.potade@linux.intel.com> | 2019-08-24 02:35:26 +0300 |
---|---|---|
committer | James Feist <james.feist@linux.intel.com> | 2019-10-24 02:18:41 +0300 |
commit | a25aeccf45933dbccfd68c633d0ae13ddd3e1962 (patch) | |
tree | 32a6686ad83d65f895bb298d8326dfa43ea2bea0 /redfish-core/lib/storage.hpp | |
parent | 02453b10810c2775236fd0ea4e2d7bc14c46645f (diff) | |
download | bmcweb-a25aeccf45933dbccfd68c633d0ae13ddd3e1962.tar.xz |
Add Storage Schema
This takes the original commit below and updates it so that it
passes the validatior, and provides the Status attribute in
redfish when appropriate.
Tested: Passed the validator
{
"@odata.context": "/redfish/v1/$metadata#Drive.Drive",
"@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_2",
"@odata.type": "#Drive.v1_2_0.Drive",
"Id": "Drive_2",
"Manufacturer": "INTEL",
"Model": "P4800X",
"Name": "Drive_2",
"PartNumber": "INTEL SSDPE21K375GA",
"SerialNumber": "PHKE722600NL375AGN",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
}
}
Original Commit Message:
-------------------------------------------------------------------
Add Storage Schema for NVMe on Redfish
This provides an implementation for the Get methods for the Storage
schemas using following classes :
- StorageCollection
- Storage
Tested:
- Ran Redfish Service Validator to verify no issues are reported.
- Tested that the NVMe drives in the system show up and proper fields
are populated with appropriate data.
- Tested with no drives present. Made sure the Storage interface shows
no drives and Drive interface returns error message.
Change-Id: Id0306ea413ac16a993110bb1a36cd95d939cff71
Signed-off-by: Nikhil Potade <nikhil.potade@linux.intel.com>
Signed-off-by: James Feist <james.feist@linux.intel.com>
Diffstat (limited to 'redfish-core/lib/storage.hpp')
-rw-r--r-- | redfish-core/lib/storage.hpp | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/redfish-core/lib/storage.hpp b/redfish-core/lib/storage.hpp new file mode 100644 index 0000000000..3c4fe4c543 --- /dev/null +++ b/redfish-core/lib/storage.hpp @@ -0,0 +1,286 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ +#pragma once + +#include <node.hpp> + +namespace redfish +{ +class StorageCollection : public Node +{ + public: + StorageCollection(CrowApp &app) : + Node(app, "/redfish/v1/Systems/system/Storage/") + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; + } + + private: + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + res.jsonValue["@odata.type"] = "#StorageCollection.StorageCollection"; + res.jsonValue["@odata.context"] = + "/redfish/v1/$metadata#StorageCollection.StorageCollection"; + res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage"; + res.jsonValue["Name"] = "Storage Collection"; + res.jsonValue["Members"] = { + {{"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}}; + res.jsonValue["Members@odata.count"] = 1; + res.end(); + } +}; + +class Storage : public Node +{ + public: + Storage(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/Storage/1") + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; + } + + private: + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage"; + res.jsonValue["@odata.context"] = + "/redfish/v1/$metadata#Storage.Storage"; + res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1"; + res.jsonValue["Name"] = "Storage Controller"; + res.jsonValue["Id"] = "1"; + + auto asyncResp = std::make_shared<AsyncResp>(res); + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec, + const std::vector<std::string> &storageList) { + nlohmann::json &storageArray = + asyncResp->res.jsonValue["Drives"]; + storageArray = nlohmann::json::array(); + asyncResp->res.jsonValue["Drives@odata.count"] = 0; + if (ec) + { + BMCWEB_LOG_ERROR << "Drive mapper call error"; + messages::internalError(asyncResp->res); + return; + } + for (const std::string &objpath : storageList) + { + std::size_t lastPos = objpath.rfind("/"); + if (lastPos == std::string::npos || + (objpath.size() <= lastPos + 1)) + { + BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; + continue; + } + + storageArray.push_back( + {{"@odata.id", + "/redfish/v1/Systems/system/Storage/1/Drive/" + + objpath.substr(lastPos + 1)}}); + } + + asyncResp->res.jsonValue["Drives@odata.count"] = + storageArray.size(); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", + "/xyz/openbmc_project/inventory", int32_t(0), + std::array<const char *, 1>{ + "xyz.openbmc_project.Inventory.Item.Drive"}); + } +}; + +class Drive : public Node +{ + public: + Drive(CrowApp &app) : + Node(app, "/redfish/v1/Systems/system/Storage/1/Drive/<str>/", + std::string()) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, + {boost::beast::http::verb::head, {{"Login"}}}, + {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, + {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; + } + + private: + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { + const std::string &driveId = params[0]; + + auto asyncResp = std::make_shared<AsyncResp>(res); + + crow::connections::systemBus->async_method_call( + [asyncResp, driveId]( + const boost::system::error_code ec, + const std::vector<std::pair< + std::string, std::vector<std::pair< + std::string, std::vector<std::string>>>>> + &subtree) { + if (ec) + { + BMCWEB_LOG_ERROR << "Drive mapper call error"; + messages::internalError(asyncResp->res); + return; + } + + auto object = std::find_if( + subtree.begin(), subtree.end(), [&driveId](auto &object) { + const std::string &path = object.first; + return boost::ends_with(path, "/" + driveId); + }); + + if (object == subtree.end()) + { + messages::resourceNotFound(asyncResp->res, "Drive", + driveId); + return; + } + + const std::string &path = object->first; + const std::vector< + std::pair<std::string, std::vector<std::string>>> + &connectionNames = object->second; + + asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive"; + asyncResp->res.jsonValue["@odata.context"] = + "/redfish/v1/$metadata#Drive.Drive"; + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Systems/system/Storage/1/Drive/" + driveId; + + if (connectionNames.size() != 1) + { + BMCWEB_LOG_ERROR << "Connection size " + << connectionNames.size() + << ", greater than 1"; + messages::internalError(asyncResp->res); + return; + } + + getMainChassisId( + asyncResp, [](const std::string &chassisId, + std::shared_ptr<AsyncResp> aRsp) { + aRsp->res.jsonValue["Links"]["Chassis"] = { + {"@odata.id", "/redfish/v1/Chassis/" + chassisId}}; + }); + + const std::string &connectionName = connectionNames[0].first; + crow::connections::systemBus->async_method_call( + [asyncResp, + driveId](const boost::system::error_code ec, + const std::vector<std::pair< + std::string, + std::variant<bool, std::string, uint64_t>>> + &propertiesList) { + if (ec) + { + // this interface isn't necessary + return; + } + for (const std::pair<std::string, + std::variant<bool, std::string, + uint64_t>> &property : + propertiesList) + { + // Store DBus properties that are also + // Redfish properties with same name and a + // string value + const std::string &propertyName = property.first; + if ((propertyName == "PartNumber") || + (propertyName == "SerialNumber") || + (propertyName == "Manufacturer") || + (propertyName == "Model")) + { + const std::string *value = + std::get_if<std::string>(&property.second); + if (value == nullptr) + { + // illegal property + messages::internalError(asyncResp->res); + continue; + } + asyncResp->res.jsonValue[propertyName] = *value; + } + } + asyncResp->res.jsonValue["Name"] = driveId; + asyncResp->res.jsonValue["Id"] = driveId; + }, + connectionName, path, "org.freedesktop.DBus.Properties", + "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset"); + + // default it to Enabled + asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; + + crow::connections::systemBus->async_method_call( + [asyncResp, path](const boost::system::error_code ec, + const std::variant<bool> present) { + // this interface isn't necessary, only check it if we + // get a good return + if (!ec) + { + const bool *enabled = std::get_if<bool>(&present); + if (enabled == nullptr) + { + BMCWEB_LOG_DEBUG << "Illegal property present"; + messages::internalError(asyncResp->res); + return; + } + if (!(*enabled)) + { + asyncResp->res.jsonValue["Status"]["State"] = + "Disabled"; + return; + } + } + + // only populate if Enabled, assume enabled unless item + // interface says otherwise + auto health = + std::make_shared<HealthPopulate>(asyncResp); + health->inventory = std::vector<std::string>{path}; + + health->populate(); + }, + connectionName, path, "org.freedesktop.DBus.Properties", + "Get", "xyz.openbmc_project.Inventory.Item", "Present"); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/inventory", int32_t(0), + std::array<const char *, 1>{ + "xyz.openbmc_project.Inventory.Item.Drive"}); + } +}; +} // namespace redfish |