blob: c57394af305788b9a8c495681f7675d5545aa044 [file] [log] [blame]
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +02001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include <boost/container/flat_map.hpp>
19#include <node.hpp>
20#include <utils/json_utils.hpp>
21
22namespace redfish
23{
24
25void getResourceList(std::shared_ptr<AsyncResp> aResp, const std::string &name,
26 const std::string &subclass,
27 const std::string &collectionName)
28{
29 BMCWEB_LOG_DEBUG << "Get available system cpu/mem resources.";
30 crow::connections::systemBus->async_method_call(
31 [name, subclass, aResp{std::move(aResp)}](
32 const boost::system::error_code ec,
33 const boost::container::flat_map<
34 std::string, boost::container::flat_map<
35 std::string, std::vector<std::string>>>
36 &subtree) {
37 if (ec)
38 {
39 BMCWEB_LOG_DEBUG << "DBUS response error";
40 messages::internalError(aResp->res);
41 return;
42 }
43 nlohmann::json &members = aResp->res.jsonValue["Members"];
44 members = nlohmann::json::array();
45
46 for (const auto &object : subtree)
47 {
48 auto iter = object.first.rfind("/");
49 if ((iter != std::string::npos) && (iter < object.first.size()))
50 {
51 members.push_back(
52 {{"@odata.id", "/redfish/v1/Systems/" + name + "/" +
53 subclass + "/" +
54 object.first.substr(iter + 1)}});
55 }
56 }
57 aResp->res.jsonValue["Members@odata.count"] = members.size();
58 },
59 "xyz.openbmc_project.ObjectMapper",
60 "/xyz/openbmc_project/object_mapper",
61 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
62 "/xyz/openbmc_project/inventory", int32_t(0),
63 std::array<const char *, 1>{collectionName.c_str()});
64}
65
66void getCpuDataByService(std::shared_ptr<AsyncResp> aResp,
67 const std::string &name, const std::string &cpuId,
68 const std::string &service, const std::string &objPath)
69{
70 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
71 crow::connections::systemBus->async_method_call(
72 [name, cpuId, aResp{std::move(aResp)}](
73 const boost::system::error_code ec,
74 const boost::container::flat_map<
75 std::string,
76 sdbusplus::message::variant<std::string, uint32_t, uint16_t>>
77 &properties) {
78 if (ec)
79 {
80 BMCWEB_LOG_DEBUG << "DBUS response error";
81 messages::internalError(aResp->res);
82
83 return;
84 }
85 aResp->res.jsonValue["Id"] = cpuId;
86 aResp->res.jsonValue["Name"] = "Processor";
87 const auto coresCountProperty =
88 properties.find("ProcessorCoreCount");
Ed Tanous883b3112018-12-06 16:13:35 -080089 if (coresCountProperty != properties.end())
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +020090 {
Ed Tanous883b3112018-12-06 16:13:35 -080091 const uint16_t *coresCount =
92 sdbusplus::message::variant_ns::get_if<uint16_t>(
93 &coresCountProperty->second);
94 if (coresCount == nullptr)
95 {
96 // Important property not in desired type
97 messages::internalError(aResp->res);
98 return;
99 }
100 if (*coresCount == 0)
101 {
102 // Slot is not populated, set status end return
103 aResp->res.jsonValue["Status"]["State"] = "Absent";
104 aResp->res.jsonValue["Status"]["Health"] = "OK";
105 // HTTP Code will be set up automatically, just return
106 return;
107 }
108
109 aResp->res.jsonValue["TotalCores"] = *coresCount;
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200110 }
111
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200112 aResp->res.jsonValue["Status"]["State"] = "Enabled";
113 aResp->res.jsonValue["Status"]["Health"] = "OK";
114
115 for (const auto &property : properties)
116 {
117 if (property.first == "ProcessorType")
118 {
119 aResp->res.jsonValue["Name"] = property.second;
120 }
121 else if (property.first == "ProcessorManufacturer")
122 {
123 aResp->res.jsonValue["Manufacturer"] = property.second;
124 const std::string *value =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800125 sdbusplus::message::variant_ns::get_if<std::string>(
126 &property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200127 if (value != nullptr)
128 {
129 // Otherwise would be unexpected.
130 if (value->find("Intel") != std::string::npos)
131 {
132 aResp->res.jsonValue["ProcessorArchitecture"] =
133 "x86";
134 aResp->res.jsonValue["InstructionSet"] = "x86-64";
135 }
Gunnar Millsb957ba52019-01-31 15:58:15 -0600136 else if (value->find("IBM") != std::string::npos)
137 {
138 aResp->res.jsonValue["ProcessorArchitecture"] =
139 "Power";
140 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
141 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200142 }
143 }
144 else if (property.first == "ProcessorMaxSpeed")
145 {
146 aResp->res.jsonValue["MaxSpeedMHz"] = property.second;
147 }
148 else if (property.first == "ProcessorThreadCount")
149 {
150 aResp->res.jsonValue["TotalThreads"] = property.second;
151 }
152 else if (property.first == "ProcessorVersion")
153 {
154 aResp->res.jsonValue["Model"] = property.second;
155 }
156 }
157 },
158 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
159}
160
161void getCpuData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
162 const std::string &cpuId)
163{
164 BMCWEB_LOG_DEBUG << "Get available system cpu resources.";
165 crow::connections::systemBus->async_method_call(
166 [name, cpuId, aResp{std::move(aResp)}](
167 const boost::system::error_code ec,
168 const boost::container::flat_map<
169 std::string, boost::container::flat_map<
170 std::string, std::vector<std::string>>>
171 &subtree) {
172 if (ec)
173 {
174 BMCWEB_LOG_DEBUG << "DBUS response error";
175 messages::internalError(aResp->res);
176 return;
177 }
178 for (const auto &object : subtree)
179 {
180 if (boost::ends_with(object.first, cpuId))
181 {
182 for (const auto &service : object.second)
183 {
184 getCpuDataByService(aResp, name, cpuId, service.first,
185 object.first);
186 return;
187 }
188 }
189 }
190 // Object not found
191 messages::resourceNotFound(aResp->res, "Processor", cpuId);
192 return;
193 },
194 "xyz.openbmc_project.ObjectMapper",
195 "/xyz/openbmc_project/object_mapper",
196 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
197 "/xyz/openbmc_project/inventory", int32_t(0),
198 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Cpu"});
199};
200
201void getDimmDataByService(std::shared_ptr<AsyncResp> aResp,
202 const std::string &name, const std::string &dimmId,
203 const std::string &service,
204 const std::string &objPath)
205{
206 BMCWEB_LOG_DEBUG << "Get available system components.";
207 crow::connections::systemBus->async_method_call(
208 [name, dimmId, aResp{std::move(aResp)}](
209 const boost::system::error_code ec,
210 const boost::container::flat_map<
211 std::string,
212 sdbusplus::message::variant<std::string, uint32_t, uint16_t>>
213 &properties) {
214 if (ec)
215 {
216 BMCWEB_LOG_DEBUG << "DBUS response error";
217 messages::internalError(aResp->res);
218
219 return;
220 }
221 aResp->res.jsonValue["Id"] = dimmId;
222 aResp->res.jsonValue["Name"] = "DIMM Slot";
223
224 const auto memorySizeProperty = properties.find("MemorySizeInKB");
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600225 if (memorySizeProperty != properties.end())
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200226 {
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600227 const uint32_t *memorySize =
228 sdbusplus::message::variant_ns::get_if<uint32_t>(
229 &memorySizeProperty->second);
230 if (memorySize == nullptr)
231 {
232 // Important property not in desired type
233 messages::internalError(aResp->res);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200234
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600235 return;
236 }
237 if (*memorySize == 0)
238 {
239 // Slot is not populated, set status end return
240 aResp->res.jsonValue["Status"]["State"] = "Absent";
241 aResp->res.jsonValue["Status"]["Health"] = "OK";
242 // HTTP Code will be set up automatically, just return
243 return;
244 }
245 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200246 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200247 aResp->res.jsonValue["Status"]["State"] = "Enabled";
248 aResp->res.jsonValue["Status"]["Health"] = "OK";
249
250 for (const auto &property : properties)
251 {
252 if (property.first == "MemoryDataWidth")
253 {
254 aResp->res.jsonValue["DataWidthBits"] = property.second;
255 }
256 else if (property.first == "MemoryType")
257 {
258 const auto *value =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800259 sdbusplus::message::variant_ns::get_if<std::string>(
260 &property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200261 if (value != nullptr)
262 {
263 aResp->res.jsonValue["MemoryDeviceType"] = *value;
264 if (boost::starts_with(*value, "DDR"))
265 {
266 aResp->res.jsonValue["MemoryType"] = "DRAM";
267 }
268 }
269 }
270 }
271 },
272 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
273}
274
275void getDimmData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
276 const std::string &dimmId)
277{
278 BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
279 crow::connections::systemBus->async_method_call(
280 [name, dimmId, aResp{std::move(aResp)}](
281 const boost::system::error_code ec,
282 const boost::container::flat_map<
283 std::string, boost::container::flat_map<
284 std::string, std::vector<std::string>>>
285 &subtree) {
286 if (ec)
287 {
288 BMCWEB_LOG_DEBUG << "DBUS response error";
289 messages::internalError(aResp->res);
290
291 return;
292 }
293 for (const auto &object : subtree)
294 {
295 if (boost::ends_with(object.first, dimmId))
296 {
297 for (const auto &service : object.second)
298 {
299 getDimmDataByService(aResp, name, dimmId, service.first,
300 object.first);
301 return;
302 }
303 }
304 }
305 // Object not found
306 messages::resourceNotFound(aResp->res, "Memory", dimmId);
307 return;
308 },
309 "xyz.openbmc_project.ObjectMapper",
310 "/xyz/openbmc_project/object_mapper",
311 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
312 "/xyz/openbmc_project/inventory", int32_t(0),
313 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Dimm"});
314};
315
316class ProcessorCollection : public Node
317{
318 public:
319 /*
320 * Default Constructor
321 */
322 ProcessorCollection(CrowApp &app) :
323 Node(app, "/redfish/v1/Systems/<str>/Processors/", std::string())
324 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200325 entityPrivileges = {
326 {boost::beast::http::verb::get, {{"Login"}}},
327 {boost::beast::http::verb::head, {{"Login"}}},
328 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
329 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
330 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
331 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
332 }
333
334 private:
335 /**
336 * Functions triggers appropriate requests on DBus
337 */
338 void doGet(crow::Response &res, const crow::Request &req,
339 const std::vector<std::string> &params) override
340 {
341 // Check if there is required param, truly entering this shall be
342 // impossible
343 if (params.size() != 1)
344 {
345 messages::internalError(res);
346 res.end();
347 return;
348 }
349 const std::string &name = params[0];
350
Ed Tanous0f74e642018-11-12 15:17:05 -0800351 res.jsonValue["@odata.type"] =
352 "#ProcessorCollection.ProcessorCollection";
353 res.jsonValue["Name"] = "Processor Collection";
354 res.jsonValue["@odata.context"] =
355 "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
356
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200357 res.jsonValue["@odata.id"] =
358 "/redfish/v1/Systems/" + name + "/Processors/";
359 auto asyncResp = std::make_shared<AsyncResp>(res);
360
361 getResourceList(asyncResp, name, "Processors",
362 "xyz.openbmc_project.Inventory.Item.Cpu");
363 }
364};
365
366class Processor : public Node
367{
368 public:
369 /*
370 * Default Constructor
371 */
372 Processor(CrowApp &app) :
373 Node(app, "/redfish/v1/Systems/<str>/Processors/<str>/", std::string(),
374 std::string())
375 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200376 entityPrivileges = {
377 {boost::beast::http::verb::get, {{"Login"}}},
378 {boost::beast::http::verb::head, {{"Login"}}},
379 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
380 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
381 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
382 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
383 }
384
385 private:
386 /**
387 * Functions triggers appropriate requests on DBus
388 */
389 void doGet(crow::Response &res, const crow::Request &req,
390 const std::vector<std::string> &params) override
391 {
392 // Check if there is required param, truly entering this shall be
393 // impossible
394 if (params.size() != 2)
395 {
396 messages::internalError(res);
397
398 res.end();
399 return;
400 }
401 const std::string &name = params[0];
402 const std::string &cpuId = params[1];
Rapkiewicz, Pawelbb3d9942018-11-22 10:59:11 +0100403 res.jsonValue["@odata.type"] = "#Processor.v1_3_1.Processor";
Ed Tanous0f74e642018-11-12 15:17:05 -0800404 res.jsonValue["@odata.context"] =
405 "/redfish/v1/$metadata#Processor.Processor";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200406 res.jsonValue["@odata.id"] =
407 "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
408
409 auto asyncResp = std::make_shared<AsyncResp>(res);
410
411 getCpuData(asyncResp, name, cpuId);
412 }
413};
414
415class MemoryCollection : public Node
416{
417 public:
418 /*
419 * Default Constructor
420 */
421 MemoryCollection(CrowApp &app) :
422 Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
423 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200424 entityPrivileges = {
425 {boost::beast::http::verb::get, {{"Login"}}},
426 {boost::beast::http::verb::head, {{"Login"}}},
427 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
428 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
429 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
430 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
431 }
432
433 private:
434 /**
435 * Functions triggers appropriate requests on DBus
436 */
437 void doGet(crow::Response &res, const crow::Request &req,
438 const std::vector<std::string> &params) override
439 {
440 // Check if there is required param, truly entering this shall be
441 // impossible
442 if (params.size() != 1)
443 {
444 messages::internalError(res);
445
446 res.end();
447 return;
448 }
449 const std::string &name = params[0];
450
Ed Tanous0f74e642018-11-12 15:17:05 -0800451 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
452 res.jsonValue["Name"] = "Memory Module Collection";
453 res.jsonValue["@odata.context"] =
454 "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200455 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
456 auto asyncResp = std::make_shared<AsyncResp>(res);
457
458 getResourceList(asyncResp, name, "Memory",
459 "xyz.openbmc_project.Inventory.Item.Dimm");
460 }
461};
462
463class Memory : public Node
464{
465 public:
466 /*
467 * Default Constructor
468 */
469 Memory(CrowApp &app) :
470 Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
471 std::string())
472 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200473 entityPrivileges = {
474 {boost::beast::http::verb::get, {{"Login"}}},
475 {boost::beast::http::verb::head, {{"Login"}}},
476 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
477 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
478 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
479 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
480 }
481
482 private:
483 /**
484 * Functions triggers appropriate requests on DBus
485 */
486 void doGet(crow::Response &res, const crow::Request &req,
487 const std::vector<std::string> &params) override
488 {
489 // Check if there is required param, truly entering this shall be
490 // impossible
491 if (params.size() != 2)
492 {
493 messages::internalError(res);
494 res.end();
495 return;
496 }
497 const std::string &name = params[0];
498 const std::string &dimmId = params[1];
499
Rapkiewicz, Pawelbb3d9942018-11-22 10:59:11 +0100500 res.jsonValue["@odata.type"] = "#Memory.v1_6_0.Memory";
Ed Tanous0f74e642018-11-12 15:17:05 -0800501 res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200502 res.jsonValue["@odata.id"] =
503 "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
504 auto asyncResp = std::make_shared<AsyncResp>(res);
505
506 getDimmData(asyncResp, name, dimmId);
507 }
508};
509
510} // namespace redfish