blob: 6001d63615d30756f19e4232bcba7dd339aca350 [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 =
96 mapbox::getPtr<const uint16_t>(coresCountProperty->second);
97 if (coresCount == nullptr)
98 {
99 // Important property not in desired type
100 messages::internalError(aResp->res);
101 return;
102 }
103 if (*coresCount == 0)
104 {
105 // Slot is not populated, set status end return
106 aResp->res.jsonValue["Status"]["State"] = "Absent";
107 aResp->res.jsonValue["Status"]["Health"] = "OK";
108 // HTTP Code will be set up automatically, just return
109 return;
110 }
111
112 aResp->res.jsonValue["TotalCores"] = *coresCount;
113 aResp->res.jsonValue["Status"]["State"] = "Enabled";
114 aResp->res.jsonValue["Status"]["Health"] = "OK";
115
116 for (const auto &property : properties)
117 {
118 if (property.first == "ProcessorType")
119 {
120 aResp->res.jsonValue["Name"] = property.second;
121 }
122 else if (property.first == "ProcessorManufacturer")
123 {
124 aResp->res.jsonValue["Manufacturer"] = property.second;
125 const std::string *value =
126 mapbox::getPtr<const std::string>(property.second);
127 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 =
227 mapbox::getPtr<const uint32_t>(memorySizeProperty->second);
228 if (memorySize == nullptr)
229 {
230 // Important property not in desired type
231 messages::internalError(aResp->res);
232
233 return;
234 }
235 if (*memorySize == 0)
236 {
237 // Slot is not populated, set status end return
238 aResp->res.jsonValue["Status"]["State"] = "Absent";
239 aResp->res.jsonValue["Status"]["Health"] = "OK";
240 // HTTP Code will be set up automatically, just return
241 return;
242 }
243 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
244 aResp->res.jsonValue["Status"]["State"] = "Enabled";
245 aResp->res.jsonValue["Status"]["Health"] = "OK";
246
247 for (const auto &property : properties)
248 {
249 if (property.first == "MemoryDataWidth")
250 {
251 aResp->res.jsonValue["DataWidthBits"] = property.second;
252 }
253 else if (property.first == "MemoryType")
254 {
255 const auto *value =
256 mapbox::getPtr<const std::string>(property.second);
257 if (value != nullptr)
258 {
259 aResp->res.jsonValue["MemoryDeviceType"] = *value;
260 if (boost::starts_with(*value, "DDR"))
261 {
262 aResp->res.jsonValue["MemoryType"] = "DRAM";
263 }
264 }
265 }
266 }
267 },
268 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
269}
270
271void getDimmData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
272 const std::string &dimmId)
273{
274 BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
275 crow::connections::systemBus->async_method_call(
276 [name, dimmId, aResp{std::move(aResp)}](
277 const boost::system::error_code ec,
278 const boost::container::flat_map<
279 std::string, boost::container::flat_map<
280 std::string, std::vector<std::string>>>
281 &subtree) {
282 if (ec)
283 {
284 BMCWEB_LOG_DEBUG << "DBUS response error";
285 messages::internalError(aResp->res);
286
287 return;
288 }
289 for (const auto &object : subtree)
290 {
291 if (boost::ends_with(object.first, dimmId))
292 {
293 for (const auto &service : object.second)
294 {
295 getDimmDataByService(aResp, name, dimmId, service.first,
296 object.first);
297 return;
298 }
299 }
300 }
301 // Object not found
302 messages::resourceNotFound(aResp->res, "Memory", dimmId);
303 return;
304 },
305 "xyz.openbmc_project.ObjectMapper",
306 "/xyz/openbmc_project/object_mapper",
307 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
308 "/xyz/openbmc_project/inventory", int32_t(0),
309 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Dimm"});
310};
311
312class ProcessorCollection : public Node
313{
314 public:
315 /*
316 * Default Constructor
317 */
318 ProcessorCollection(CrowApp &app) :
319 Node(app, "/redfish/v1/Systems/<str>/Processors/", std::string())
320 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200321 entityPrivileges = {
322 {boost::beast::http::verb::get, {{"Login"}}},
323 {boost::beast::http::verb::head, {{"Login"}}},
324 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
325 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
326 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
327 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
328 }
329
330 private:
331 /**
332 * Functions triggers appropriate requests on DBus
333 */
334 void doGet(crow::Response &res, const crow::Request &req,
335 const std::vector<std::string> &params) override
336 {
337 // Check if there is required param, truly entering this shall be
338 // impossible
339 if (params.size() != 1)
340 {
341 messages::internalError(res);
342 res.end();
343 return;
344 }
345 const std::string &name = params[0];
346
Ed Tanous0f74e642018-11-12 15:17:05 -0800347 res.jsonValue["@odata.type"] =
348 "#ProcessorCollection.ProcessorCollection";
349 res.jsonValue["Name"] = "Processor Collection";
350 res.jsonValue["@odata.context"] =
351 "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
352
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200353 res.jsonValue["@odata.id"] =
354 "/redfish/v1/Systems/" + name + "/Processors/";
355 auto asyncResp = std::make_shared<AsyncResp>(res);
356
357 getResourceList(asyncResp, name, "Processors",
358 "xyz.openbmc_project.Inventory.Item.Cpu");
359 }
360};
361
362class Processor : public Node
363{
364 public:
365 /*
366 * Default Constructor
367 */
368 Processor(CrowApp &app) :
369 Node(app, "/redfish/v1/Systems/<str>/Processors/<str>/", std::string(),
370 std::string())
371 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200372 entityPrivileges = {
373 {boost::beast::http::verb::get, {{"Login"}}},
374 {boost::beast::http::verb::head, {{"Login"}}},
375 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
376 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
377 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
378 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
379 }
380
381 private:
382 /**
383 * Functions triggers appropriate requests on DBus
384 */
385 void doGet(crow::Response &res, const crow::Request &req,
386 const std::vector<std::string> &params) override
387 {
388 // Check if there is required param, truly entering this shall be
389 // impossible
390 if (params.size() != 2)
391 {
392 messages::internalError(res);
393
394 res.end();
395 return;
396 }
397 const std::string &name = params[0];
398 const std::string &cpuId = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -0800399 res.jsonValue["@odata.type"] = "#Processor.v1_1_0.Processor";
400 res.jsonValue["@odata.context"] =
401 "/redfish/v1/$metadata#Processor.Processor";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200402 res.jsonValue["@odata.id"] =
403 "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
404
405 auto asyncResp = std::make_shared<AsyncResp>(res);
406
407 getCpuData(asyncResp, name, cpuId);
408 }
409};
410
411class MemoryCollection : public Node
412{
413 public:
414 /*
415 * Default Constructor
416 */
417 MemoryCollection(CrowApp &app) :
418 Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
419 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200420 entityPrivileges = {
421 {boost::beast::http::verb::get, {{"Login"}}},
422 {boost::beast::http::verb::head, {{"Login"}}},
423 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
424 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
425 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
426 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
427 }
428
429 private:
430 /**
431 * Functions triggers appropriate requests on DBus
432 */
433 void doGet(crow::Response &res, const crow::Request &req,
434 const std::vector<std::string> &params) override
435 {
436 // Check if there is required param, truly entering this shall be
437 // impossible
438 if (params.size() != 1)
439 {
440 messages::internalError(res);
441
442 res.end();
443 return;
444 }
445 const std::string &name = params[0];
446
Ed Tanous0f74e642018-11-12 15:17:05 -0800447 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
448 res.jsonValue["Name"] = "Memory Module Collection";
449 res.jsonValue["@odata.context"] =
450 "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200451 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
452 auto asyncResp = std::make_shared<AsyncResp>(res);
453
454 getResourceList(asyncResp, name, "Memory",
455 "xyz.openbmc_project.Inventory.Item.Dimm");
456 }
457};
458
459class Memory : public Node
460{
461 public:
462 /*
463 * Default Constructor
464 */
465 Memory(CrowApp &app) :
466 Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
467 std::string())
468 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200469 entityPrivileges = {
470 {boost::beast::http::verb::get, {{"Login"}}},
471 {boost::beast::http::verb::head, {{"Login"}}},
472 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
473 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
474 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
475 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
476 }
477
478 private:
479 /**
480 * Functions triggers appropriate requests on DBus
481 */
482 void doGet(crow::Response &res, const crow::Request &req,
483 const std::vector<std::string> &params) override
484 {
485 // Check if there is required param, truly entering this shall be
486 // impossible
487 if (params.size() != 2)
488 {
489 messages::internalError(res);
490 res.end();
491 return;
492 }
493 const std::string &name = params[0];
494 const std::string &dimmId = params[1];
495
Ed Tanous0f74e642018-11-12 15:17:05 -0800496 res.jsonValue["@odata.type"] = "#Memory.v1_2_0.Memory";
497 res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200498 res.jsonValue["@odata.id"] =
499 "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
500 auto asyncResp = std::make_shared<AsyncResp>(res);
501
502 getDimmData(asyncResp, name, dimmId);
503 }
504};
505
506} // namespace redfish