Initial implementation of processors and memory schema
This is an initial implementations of GET methods for
several schemas:
* ProcessorCollection
* Processor
* MemoryCollection
* Memory
It fetches data from Smbios service.
Tested:
* Compiance report
* Manual walk through selected schemas.
Change-Id: I11e00d0982248f2307e24b9a246ac60672dda8a1
Signed-off-by: Rapkiewicz, Pawel <pawel.rapkiewicz@intel.com>
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 8a8b656..8c3885f 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -17,6 +17,7 @@
#include "../lib/account_service.hpp"
#include "../lib/chassis.hpp"
+#include "../lib/cpudimm.hpp"
#include "../lib/ethernet.hpp"
#include "../lib/log_services.hpp"
#include "../lib/managers.hpp"
@@ -85,6 +86,11 @@
#endif // BMCWEB_ENABLE_REDFISH_RAW_PECI
#endif // BMCWEB_ENABLE_REDFISH_CPU_LOG
+ nodes.emplace_back(std::make_unique<ProcessorCollection>(app));
+ nodes.emplace_back(std::make_unique<Processor>(app));
+ nodes.emplace_back(std::make_unique<MemoryCollection>(app));
+ nodes.emplace_back(std::make_unique<Memory>(app));
+
nodes.emplace_back(std::make_unique<SystemsCollection>(app));
nodes.emplace_back(std::make_unique<Systems>(app));
nodes.emplace_back(std::make_unique<SystemActionsReset>(app));
diff --git a/redfish-core/lib/cpudimm.hpp b/redfish-core/lib/cpudimm.hpp
new file mode 100644
index 0000000..120b2b5
--- /dev/null
+++ b/redfish-core/lib/cpudimm.hpp
@@ -0,0 +1,513 @@
+/*
+// Copyright (c) 2018 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 <boost/container/flat_map.hpp>
+#include <node.hpp>
+#include <utils/json_utils.hpp>
+
+namespace redfish
+{
+
+void getResourceList(std::shared_ptr<AsyncResp> aResp, const std::string &name,
+ const std::string &subclass,
+ const std::string &collectionName)
+{
+ BMCWEB_LOG_DEBUG << "Get available system cpu/mem resources.";
+ crow::connections::systemBus->async_method_call(
+ [name, subclass, aResp{std::move(aResp)}](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, boost::container::flat_map<
+ std::string, std::vector<std::string>>>
+ &subtree) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error";
+ messages::internalError(aResp->res);
+ return;
+ }
+ nlohmann::json &members = aResp->res.jsonValue["Members"];
+ members = nlohmann::json::array();
+
+ for (const auto &object : subtree)
+ {
+ auto iter = object.first.rfind("/");
+ if ((iter != std::string::npos) && (iter < object.first.size()))
+ {
+ members.push_back(
+ {{"@odata.id", "/redfish/v1/Systems/" + name + "/" +
+ subclass + "/" +
+ object.first.substr(iter + 1)}});
+ }
+ }
+ aResp->res.jsonValue["Members@odata.count"] = members.size();
+ },
+ "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>{collectionName.c_str()});
+}
+
+void getCpuDataByService(std::shared_ptr<AsyncResp> aResp,
+ const std::string &name, const std::string &cpuId,
+ const std::string &service, const std::string &objPath)
+{
+ BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
+ crow::connections::systemBus->async_method_call(
+ [name, cpuId, aResp{std::move(aResp)}](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string,
+ sdbusplus::message::variant<std::string, uint32_t, uint16_t>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error";
+ messages::internalError(aResp->res);
+
+ return;
+ }
+ aResp->res.jsonValue["Id"] = cpuId;
+ aResp->res.jsonValue["Name"] = "Processor";
+ const auto coresCountProperty =
+ properties.find("ProcessorCoreCount");
+ if (coresCountProperty == properties.end())
+ {
+ // Important property not in result
+ messages::internalError(aResp->res);
+ return;
+ }
+ const uint16_t *coresCount =
+ mapbox::getPtr<const uint16_t>(coresCountProperty->second);
+ if (coresCount == nullptr)
+ {
+ // Important property not in desired type
+ messages::internalError(aResp->res);
+ return;
+ }
+ if (*coresCount == 0)
+ {
+ // Slot is not populated, set status end return
+ aResp->res.jsonValue["Status"]["State"] = "Absent";
+ aResp->res.jsonValue["Status"]["Health"] = "OK";
+ // HTTP Code will be set up automatically, just return
+ return;
+ }
+
+ aResp->res.jsonValue["TotalCores"] = *coresCount;
+ aResp->res.jsonValue["Status"]["State"] = "Enabled";
+ aResp->res.jsonValue["Status"]["Health"] = "OK";
+
+ for (const auto &property : properties)
+ {
+ if (property.first == "ProcessorType")
+ {
+ aResp->res.jsonValue["Name"] = property.second;
+ }
+ else if (property.first == "ProcessorManufacturer")
+ {
+ aResp->res.jsonValue["Manufacturer"] = property.second;
+ const std::string *value =
+ mapbox::getPtr<const std::string>(property.second);
+ if (value != nullptr)
+ {
+ // Otherwise would be unexpected.
+ if (value->find("Intel") != std::string::npos)
+ {
+ aResp->res.jsonValue["ProcessorArchitecture"] =
+ "x86";
+ aResp->res.jsonValue["InstructionSet"] = "x86-64";
+ }
+ }
+ }
+ else if (property.first == "ProcessorMaxSpeed")
+ {
+ aResp->res.jsonValue["MaxSpeedMHz"] = property.second;
+ }
+ else if (property.first == "ProcessorThreadCount")
+ {
+ aResp->res.jsonValue["TotalThreads"] = property.second;
+ }
+ else if (property.first == "ProcessorVersion")
+ {
+ aResp->res.jsonValue["Model"] = property.second;
+ }
+ }
+ },
+ service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
+}
+
+void getCpuData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
+ const std::string &cpuId)
+{
+ BMCWEB_LOG_DEBUG << "Get available system cpu resources.";
+ crow::connections::systemBus->async_method_call(
+ [name, cpuId, aResp{std::move(aResp)}](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, boost::container::flat_map<
+ std::string, std::vector<std::string>>>
+ &subtree) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error";
+ messages::internalError(aResp->res);
+ return;
+ }
+ for (const auto &object : subtree)
+ {
+ if (boost::ends_with(object.first, cpuId))
+ {
+ for (const auto &service : object.second)
+ {
+ getCpuDataByService(aResp, name, cpuId, service.first,
+ object.first);
+ return;
+ }
+ }
+ }
+ // Object not found
+ messages::resourceNotFound(aResp->res, "Processor", cpuId);
+ return;
+ },
+ "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.Cpu"});
+};
+
+void getDimmDataByService(std::shared_ptr<AsyncResp> aResp,
+ const std::string &name, const std::string &dimmId,
+ const std::string &service,
+ const std::string &objPath)
+{
+ BMCWEB_LOG_DEBUG << "Get available system components.";
+ crow::connections::systemBus->async_method_call(
+ [name, dimmId, aResp{std::move(aResp)}](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string,
+ sdbusplus::message::variant<std::string, uint32_t, uint16_t>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error";
+ messages::internalError(aResp->res);
+
+ return;
+ }
+ aResp->res.jsonValue["Id"] = dimmId;
+ aResp->res.jsonValue["Name"] = "DIMM Slot";
+
+ const auto memorySizeProperty = properties.find("MemorySizeInKB");
+ if (memorySizeProperty == properties.end())
+ {
+ // Important property not in result
+ messages::internalError(aResp->res);
+
+ return;
+ }
+ const uint32_t *memorySize =
+ mapbox::getPtr<const uint32_t>(memorySizeProperty->second);
+ if (memorySize == nullptr)
+ {
+ // Important property not in desired type
+ messages::internalError(aResp->res);
+
+ return;
+ }
+ if (*memorySize == 0)
+ {
+ // Slot is not populated, set status end return
+ aResp->res.jsonValue["Status"]["State"] = "Absent";
+ aResp->res.jsonValue["Status"]["Health"] = "OK";
+ // HTTP Code will be set up automatically, just return
+ return;
+ }
+ aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
+ aResp->res.jsonValue["Status"]["State"] = "Enabled";
+ aResp->res.jsonValue["Status"]["Health"] = "OK";
+
+ for (const auto &property : properties)
+ {
+ if (property.first == "MemoryDataWidth")
+ {
+ aResp->res.jsonValue["DataWidthBits"] = property.second;
+ }
+ else if (property.first == "MemoryType")
+ {
+ const auto *value =
+ mapbox::getPtr<const std::string>(property.second);
+ if (value != nullptr)
+ {
+ aResp->res.jsonValue["MemoryDeviceType"] = *value;
+ if (boost::starts_with(*value, "DDR"))
+ {
+ aResp->res.jsonValue["MemoryType"] = "DRAM";
+ }
+ }
+ }
+ }
+ },
+ service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
+}
+
+void getDimmData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
+ const std::string &dimmId)
+{
+ BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
+ crow::connections::systemBus->async_method_call(
+ [name, dimmId, aResp{std::move(aResp)}](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, boost::container::flat_map<
+ std::string, std::vector<std::string>>>
+ &subtree) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error";
+ messages::internalError(aResp->res);
+
+ return;
+ }
+ for (const auto &object : subtree)
+ {
+ if (boost::ends_with(object.first, dimmId))
+ {
+ for (const auto &service : object.second)
+ {
+ getDimmDataByService(aResp, name, dimmId, service.first,
+ object.first);
+ return;
+ }
+ }
+ }
+ // Object not found
+ messages::resourceNotFound(aResp->res, "Memory", dimmId);
+ return;
+ },
+ "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.Dimm"});
+};
+
+class ProcessorCollection : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ ProcessorCollection(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/<str>/Processors/", std::string())
+ {
+
+ Node::json["@odata.type"] = "#ProcessorCollection.ProcessorCollection";
+ Node::json["Name"] = "Processor Collection";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
+ 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:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> ¶ms) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible
+ if (params.size() != 1)
+ {
+ messages::internalError(res);
+ res.end();
+ return;
+ }
+ const std::string &name = params[0];
+
+ res.jsonValue = Node::json;
+ res.jsonValue["@odata.id"] =
+ "/redfish/v1/Systems/" + name + "/Processors/";
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+
+ getResourceList(asyncResp, name, "Processors",
+ "xyz.openbmc_project.Inventory.Item.Cpu");
+ }
+};
+
+class Processor : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ Processor(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/<str>/Processors/<str>/", std::string(),
+ std::string())
+ {
+
+ Node::json["@odata.type"] = "#Processor.v1_1_0.Processor";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#Processor.Processor";
+ 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:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> ¶ms) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible
+ if (params.size() != 2)
+ {
+ messages::internalError(res);
+
+ res.end();
+ return;
+ }
+ const std::string &name = params[0];
+ const std::string &cpuId = params[1];
+
+ res.jsonValue = Node::json;
+ res.jsonValue["@odata.id"] =
+ "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
+
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+
+ getCpuData(asyncResp, name, cpuId);
+ }
+};
+
+class MemoryCollection : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ MemoryCollection(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
+ {
+
+ Node::json["@odata.type"] = "#MemoryCollection.MemoryCollection";
+ Node::json["Name"] = "Memory Module Collection";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
+ 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:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> ¶ms) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible
+ if (params.size() != 1)
+ {
+ messages::internalError(res);
+
+ res.end();
+ return;
+ }
+ const std::string &name = params[0];
+
+ res.jsonValue = Node::json;
+ res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+
+ getResourceList(asyncResp, name, "Memory",
+ "xyz.openbmc_project.Inventory.Item.Dimm");
+ }
+};
+
+class Memory : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ Memory(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
+ std::string())
+ {
+
+ Node::json["@odata.type"] = "#Memory.v1_2_0.Memory";
+ Node::json["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
+ 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:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> ¶ms) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible
+ if (params.size() != 2)
+ {
+ messages::internalError(res);
+ res.end();
+ return;
+ }
+ const std::string &name = params[0];
+ const std::string &dimmId = params[1];
+
+ res.jsonValue = Node::json;
+ res.jsonValue["@odata.id"] =
+ "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+
+ getDimmData(asyncResp, name, dimmId);
+ }
+};
+
+} // namespace redfish
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 027c276..4ab4eb9 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -701,6 +701,10 @@
res.jsonValue = Node::json;
res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
+ res.jsonValue["Processors"] = {
+ {"@odata.id", "/redfish/v1/Systems/" + name + "/Processors"}};
+ res.jsonValue["Memory"] = {
+ {"@odata.id", "/redfish/v1/Systems/" + name + "/Memory"}};
// TODO Need to support ForceRestart.
res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
{"target",