blob: ef73150496edad87d4d6ca74e1f0d23dc506b3d7 [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");
89 if (coresCountProperty == properties.end())
90 {
91 // Important property not in result
92 messages::internalError(aResp->res);
93 return;
94 }
95 const uint16_t *coresCount =
Ed Tanous1b6b96c2018-11-30 11:35:41 -080096 sdbusplus::message::variant_ns::get_if<uint16_t>(
97 &coresCountProperty->second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +020098 if (coresCount == nullptr)
99 {
100 // Important property not in desired type
101 messages::internalError(aResp->res);
102 return;
103 }
104 if (*coresCount == 0)
105 {
106 // Slot is not populated, set status end return
107 aResp->res.jsonValue["Status"]["State"] = "Absent";
108 aResp->res.jsonValue["Status"]["Health"] = "OK";
109 // HTTP Code will be set up automatically, just return
110 return;
111 }
112
113 aResp->res.jsonValue["TotalCores"] = *coresCount;
114 aResp->res.jsonValue["Status"]["State"] = "Enabled";
115 aResp->res.jsonValue["Status"]["Health"] = "OK";
116
117 for (const auto &property : properties)
118 {
119 if (property.first == "ProcessorType")
120 {
121 aResp->res.jsonValue["Name"] = property.second;
122 }
123 else if (property.first == "ProcessorManufacturer")
124 {
125 aResp->res.jsonValue["Manufacturer"] = property.second;
126 const std::string *value =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800127 sdbusplus::message::variant_ns::get_if<std::string>(
128 &property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200129 if (value != nullptr)
130 {
131 // Otherwise would be unexpected.
132 if (value->find("Intel") != std::string::npos)
133 {
134 aResp->res.jsonValue["ProcessorArchitecture"] =
135 "x86";
136 aResp->res.jsonValue["InstructionSet"] = "x86-64";
137 }
138 }
139 }
140 else if (property.first == "ProcessorMaxSpeed")
141 {
142 aResp->res.jsonValue["MaxSpeedMHz"] = property.second;
143 }
144 else if (property.first == "ProcessorThreadCount")
145 {
146 aResp->res.jsonValue["TotalThreads"] = property.second;
147 }
148 else if (property.first == "ProcessorVersion")
149 {
150 aResp->res.jsonValue["Model"] = property.second;
151 }
152 }
153 },
154 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
155}
156
157void getCpuData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
158 const std::string &cpuId)
159{
160 BMCWEB_LOG_DEBUG << "Get available system cpu resources.";
161 crow::connections::systemBus->async_method_call(
162 [name, cpuId, aResp{std::move(aResp)}](
163 const boost::system::error_code ec,
164 const boost::container::flat_map<
165 std::string, boost::container::flat_map<
166 std::string, std::vector<std::string>>>
167 &subtree) {
168 if (ec)
169 {
170 BMCWEB_LOG_DEBUG << "DBUS response error";
171 messages::internalError(aResp->res);
172 return;
173 }
174 for (const auto &object : subtree)
175 {
176 if (boost::ends_with(object.first, cpuId))
177 {
178 for (const auto &service : object.second)
179 {
180 getCpuDataByService(aResp, name, cpuId, service.first,
181 object.first);
182 return;
183 }
184 }
185 }
186 // Object not found
187 messages::resourceNotFound(aResp->res, "Processor", cpuId);
188 return;
189 },
190 "xyz.openbmc_project.ObjectMapper",
191 "/xyz/openbmc_project/object_mapper",
192 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
193 "/xyz/openbmc_project/inventory", int32_t(0),
194 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Cpu"});
195};
196
197void getDimmDataByService(std::shared_ptr<AsyncResp> aResp,
198 const std::string &name, const std::string &dimmId,
199 const std::string &service,
200 const std::string &objPath)
201{
202 BMCWEB_LOG_DEBUG << "Get available system components.";
203 crow::connections::systemBus->async_method_call(
204 [name, dimmId, aResp{std::move(aResp)}](
205 const boost::system::error_code ec,
206 const boost::container::flat_map<
207 std::string,
208 sdbusplus::message::variant<std::string, uint32_t, uint16_t>>
209 &properties) {
210 if (ec)
211 {
212 BMCWEB_LOG_DEBUG << "DBUS response error";
213 messages::internalError(aResp->res);
214
215 return;
216 }
217 aResp->res.jsonValue["Id"] = dimmId;
218 aResp->res.jsonValue["Name"] = "DIMM Slot";
219
220 const auto memorySizeProperty = properties.find("MemorySizeInKB");
221 if (memorySizeProperty == properties.end())
222 {
223 // Important property not in result
224 messages::internalError(aResp->res);
225
226 return;
227 }
228 const uint32_t *memorySize =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800229 sdbusplus::message::variant_ns::get_if<uint32_t>(
230 &memorySizeProperty->second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200231 if (memorySize == nullptr)
232 {
233 // Important property not in desired type
234 messages::internalError(aResp->res);
235
236 return;
237 }
238 if (*memorySize == 0)
239 {
240 // Slot is not populated, set status end return
241 aResp->res.jsonValue["Status"]["State"] = "Absent";
242 aResp->res.jsonValue["Status"]["Health"] = "OK";
243 // HTTP Code will be set up automatically, just return
244 return;
245 }
246 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
247 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];
Ed Tanous0f74e642018-11-12 15:17:05 -0800403 res.jsonValue["@odata.type"] = "#Processor.v1_1_0.Processor";
404 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
Ed Tanous0f74e642018-11-12 15:17:05 -0800500 res.jsonValue["@odata.type"] = "#Memory.v1_2_0.Memory";
501 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