blob: ca2f164b2760458dc31253a43fc9d573f7790be1 [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 }
136 }
137 }
138 else if (property.first == "ProcessorMaxSpeed")
139 {
140 aResp->res.jsonValue["MaxSpeedMHz"] = property.second;
141 }
142 else if (property.first == "ProcessorThreadCount")
143 {
144 aResp->res.jsonValue["TotalThreads"] = property.second;
145 }
146 else if (property.first == "ProcessorVersion")
147 {
148 aResp->res.jsonValue["Model"] = property.second;
149 }
150 }
151 },
152 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
153}
154
155void getCpuData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
156 const std::string &cpuId)
157{
158 BMCWEB_LOG_DEBUG << "Get available system cpu resources.";
159 crow::connections::systemBus->async_method_call(
160 [name, cpuId, aResp{std::move(aResp)}](
161 const boost::system::error_code ec,
162 const boost::container::flat_map<
163 std::string, boost::container::flat_map<
164 std::string, std::vector<std::string>>>
165 &subtree) {
166 if (ec)
167 {
168 BMCWEB_LOG_DEBUG << "DBUS response error";
169 messages::internalError(aResp->res);
170 return;
171 }
172 for (const auto &object : subtree)
173 {
174 if (boost::ends_with(object.first, cpuId))
175 {
176 for (const auto &service : object.second)
177 {
178 getCpuDataByService(aResp, name, cpuId, service.first,
179 object.first);
180 return;
181 }
182 }
183 }
184 // Object not found
185 messages::resourceNotFound(aResp->res, "Processor", cpuId);
186 return;
187 },
188 "xyz.openbmc_project.ObjectMapper",
189 "/xyz/openbmc_project/object_mapper",
190 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
191 "/xyz/openbmc_project/inventory", int32_t(0),
192 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Cpu"});
193};
194
195void getDimmDataByService(std::shared_ptr<AsyncResp> aResp,
196 const std::string &name, const std::string &dimmId,
197 const std::string &service,
198 const std::string &objPath)
199{
200 BMCWEB_LOG_DEBUG << "Get available system components.";
201 crow::connections::systemBus->async_method_call(
202 [name, dimmId, aResp{std::move(aResp)}](
203 const boost::system::error_code ec,
204 const boost::container::flat_map<
205 std::string,
206 sdbusplus::message::variant<std::string, uint32_t, uint16_t>>
207 &properties) {
208 if (ec)
209 {
210 BMCWEB_LOG_DEBUG << "DBUS response error";
211 messages::internalError(aResp->res);
212
213 return;
214 }
215 aResp->res.jsonValue["Id"] = dimmId;
216 aResp->res.jsonValue["Name"] = "DIMM Slot";
217
218 const auto memorySizeProperty = properties.find("MemorySizeInKB");
219 if (memorySizeProperty == properties.end())
220 {
221 // Important property not in result
222 messages::internalError(aResp->res);
223
224 return;
225 }
226 const uint32_t *memorySize =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800227 sdbusplus::message::variant_ns::get_if<uint32_t>(
228 &memorySizeProperty->second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200229 if (memorySize == nullptr)
230 {
231 // Important property not in desired type
232 messages::internalError(aResp->res);
233
234 return;
235 }
236 if (*memorySize == 0)
237 {
238 // Slot is not populated, set status end return
239 aResp->res.jsonValue["Status"]["State"] = "Absent";
240 aResp->res.jsonValue["Status"]["Health"] = "OK";
241 // HTTP Code will be set up automatically, just return
242 return;
243 }
244 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
245 aResp->res.jsonValue["Status"]["State"] = "Enabled";
246 aResp->res.jsonValue["Status"]["Health"] = "OK";
247
248 for (const auto &property : properties)
249 {
250 if (property.first == "MemoryDataWidth")
251 {
252 aResp->res.jsonValue["DataWidthBits"] = property.second;
253 }
254 else if (property.first == "MemoryType")
255 {
256 const auto *value =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800257 sdbusplus::message::variant_ns::get_if<std::string>(
258 &property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200259 if (value != nullptr)
260 {
261 aResp->res.jsonValue["MemoryDeviceType"] = *value;
262 if (boost::starts_with(*value, "DDR"))
263 {
264 aResp->res.jsonValue["MemoryType"] = "DRAM";
265 }
266 }
267 }
268 }
269 },
270 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
271}
272
273void getDimmData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
274 const std::string &dimmId)
275{
276 BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
277 crow::connections::systemBus->async_method_call(
278 [name, dimmId, aResp{std::move(aResp)}](
279 const boost::system::error_code ec,
280 const boost::container::flat_map<
281 std::string, boost::container::flat_map<
282 std::string, std::vector<std::string>>>
283 &subtree) {
284 if (ec)
285 {
286 BMCWEB_LOG_DEBUG << "DBUS response error";
287 messages::internalError(aResp->res);
288
289 return;
290 }
291 for (const auto &object : subtree)
292 {
293 if (boost::ends_with(object.first, dimmId))
294 {
295 for (const auto &service : object.second)
296 {
297 getDimmDataByService(aResp, name, dimmId, service.first,
298 object.first);
299 return;
300 }
301 }
302 }
303 // Object not found
304 messages::resourceNotFound(aResp->res, "Memory", dimmId);
305 return;
306 },
307 "xyz.openbmc_project.ObjectMapper",
308 "/xyz/openbmc_project/object_mapper",
309 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
310 "/xyz/openbmc_project/inventory", int32_t(0),
311 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Dimm"});
312};
313
314class ProcessorCollection : public Node
315{
316 public:
317 /*
318 * Default Constructor
319 */
320 ProcessorCollection(CrowApp &app) :
321 Node(app, "/redfish/v1/Systems/<str>/Processors/", std::string())
322 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200323 entityPrivileges = {
324 {boost::beast::http::verb::get, {{"Login"}}},
325 {boost::beast::http::verb::head, {{"Login"}}},
326 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
327 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
328 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
329 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
330 }
331
332 private:
333 /**
334 * Functions triggers appropriate requests on DBus
335 */
336 void doGet(crow::Response &res, const crow::Request &req,
337 const std::vector<std::string> &params) override
338 {
339 // Check if there is required param, truly entering this shall be
340 // impossible
341 if (params.size() != 1)
342 {
343 messages::internalError(res);
344 res.end();
345 return;
346 }
347 const std::string &name = params[0];
348
Ed Tanous0f74e642018-11-12 15:17:05 -0800349 res.jsonValue["@odata.type"] =
350 "#ProcessorCollection.ProcessorCollection";
351 res.jsonValue["Name"] = "Processor Collection";
352 res.jsonValue["@odata.context"] =
353 "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
354
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200355 res.jsonValue["@odata.id"] =
356 "/redfish/v1/Systems/" + name + "/Processors/";
357 auto asyncResp = std::make_shared<AsyncResp>(res);
358
359 getResourceList(asyncResp, name, "Processors",
360 "xyz.openbmc_project.Inventory.Item.Cpu");
361 }
362};
363
364class Processor : public Node
365{
366 public:
367 /*
368 * Default Constructor
369 */
370 Processor(CrowApp &app) :
371 Node(app, "/redfish/v1/Systems/<str>/Processors/<str>/", std::string(),
372 std::string())
373 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200374 entityPrivileges = {
375 {boost::beast::http::verb::get, {{"Login"}}},
376 {boost::beast::http::verb::head, {{"Login"}}},
377 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
378 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
379 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
380 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
381 }
382
383 private:
384 /**
385 * Functions triggers appropriate requests on DBus
386 */
387 void doGet(crow::Response &res, const crow::Request &req,
388 const std::vector<std::string> &params) override
389 {
390 // Check if there is required param, truly entering this shall be
391 // impossible
392 if (params.size() != 2)
393 {
394 messages::internalError(res);
395
396 res.end();
397 return;
398 }
399 const std::string &name = params[0];
400 const std::string &cpuId = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -0800401 res.jsonValue["@odata.type"] = "#Processor.v1_1_0.Processor";
402 res.jsonValue["@odata.context"] =
403 "/redfish/v1/$metadata#Processor.Processor";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200404 res.jsonValue["@odata.id"] =
405 "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
406
407 auto asyncResp = std::make_shared<AsyncResp>(res);
408
409 getCpuData(asyncResp, name, cpuId);
410 }
411};
412
413class MemoryCollection : public Node
414{
415 public:
416 /*
417 * Default Constructor
418 */
419 MemoryCollection(CrowApp &app) :
420 Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
421 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200422 entityPrivileges = {
423 {boost::beast::http::verb::get, {{"Login"}}},
424 {boost::beast::http::verb::head, {{"Login"}}},
425 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
426 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
427 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
428 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
429 }
430
431 private:
432 /**
433 * Functions triggers appropriate requests on DBus
434 */
435 void doGet(crow::Response &res, const crow::Request &req,
436 const std::vector<std::string> &params) override
437 {
438 // Check if there is required param, truly entering this shall be
439 // impossible
440 if (params.size() != 1)
441 {
442 messages::internalError(res);
443
444 res.end();
445 return;
446 }
447 const std::string &name = params[0];
448
Ed Tanous0f74e642018-11-12 15:17:05 -0800449 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
450 res.jsonValue["Name"] = "Memory Module Collection";
451 res.jsonValue["@odata.context"] =
452 "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200453 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
454 auto asyncResp = std::make_shared<AsyncResp>(res);
455
456 getResourceList(asyncResp, name, "Memory",
457 "xyz.openbmc_project.Inventory.Item.Dimm");
458 }
459};
460
461class Memory : public Node
462{
463 public:
464 /*
465 * Default Constructor
466 */
467 Memory(CrowApp &app) :
468 Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
469 std::string())
470 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200471 entityPrivileges = {
472 {boost::beast::http::verb::get, {{"Login"}}},
473 {boost::beast::http::verb::head, {{"Login"}}},
474 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
475 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
476 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
477 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
478 }
479
480 private:
481 /**
482 * Functions triggers appropriate requests on DBus
483 */
484 void doGet(crow::Response &res, const crow::Request &req,
485 const std::vector<std::string> &params) override
486 {
487 // Check if there is required param, truly entering this shall be
488 // impossible
489 if (params.size() != 2)
490 {
491 messages::internalError(res);
492 res.end();
493 return;
494 }
495 const std::string &name = params[0];
496 const std::string &dimmId = params[1];
497
Ed Tanous0f74e642018-11-12 15:17:05 -0800498 res.jsonValue["@odata.type"] = "#Memory.v1_2_0.Memory";
499 res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200500 res.jsonValue["@odata.id"] =
501 "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
502 auto asyncResp = std::make_shared<AsyncResp>(res);
503
504 getDimmData(asyncResp, name, dimmId);
505 }
506};
507
508} // namespace redfish