blob: 120b2b5239d1923e9add2d4f4a2ce8eab3159bd6 [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 {
321
322 Node::json["@odata.type"] = "#ProcessorCollection.ProcessorCollection";
323 Node::json["Name"] = "Processor Collection";
324 Node::json["@odata.context"] =
325 "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
326 entityPrivileges = {
327 {boost::beast::http::verb::get, {{"Login"}}},
328 {boost::beast::http::verb::head, {{"Login"}}},
329 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
330 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
331 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
332 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
333 }
334
335 private:
336 /**
337 * Functions triggers appropriate requests on DBus
338 */
339 void doGet(crow::Response &res, const crow::Request &req,
340 const std::vector<std::string> &params) override
341 {
342 // Check if there is required param, truly entering this shall be
343 // impossible
344 if (params.size() != 1)
345 {
346 messages::internalError(res);
347 res.end();
348 return;
349 }
350 const std::string &name = params[0];
351
352 res.jsonValue = Node::json;
353 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 {
372
373 Node::json["@odata.type"] = "#Processor.v1_1_0.Processor";
374 Node::json["@odata.context"] =
375 "/redfish/v1/$metadata#Processor.Processor";
376 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];
403
404 res.jsonValue = Node::json;
405 res.jsonValue["@odata.id"] =
406 "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
407
408 auto asyncResp = std::make_shared<AsyncResp>(res);
409
410 getCpuData(asyncResp, name, cpuId);
411 }
412};
413
414class MemoryCollection : public Node
415{
416 public:
417 /*
418 * Default Constructor
419 */
420 MemoryCollection(CrowApp &app) :
421 Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
422 {
423
424 Node::json["@odata.type"] = "#MemoryCollection.MemoryCollection";
425 Node::json["Name"] = "Memory Module Collection";
426 Node::json["@odata.context"] =
427 "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
428 entityPrivileges = {
429 {boost::beast::http::verb::get, {{"Login"}}},
430 {boost::beast::http::verb::head, {{"Login"}}},
431 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
432 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
433 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
434 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
435 }
436
437 private:
438 /**
439 * Functions triggers appropriate requests on DBus
440 */
441 void doGet(crow::Response &res, const crow::Request &req,
442 const std::vector<std::string> &params) override
443 {
444 // Check if there is required param, truly entering this shall be
445 // impossible
446 if (params.size() != 1)
447 {
448 messages::internalError(res);
449
450 res.end();
451 return;
452 }
453 const std::string &name = params[0];
454
455 res.jsonValue = Node::json;
456 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
457 auto asyncResp = std::make_shared<AsyncResp>(res);
458
459 getResourceList(asyncResp, name, "Memory",
460 "xyz.openbmc_project.Inventory.Item.Dimm");
461 }
462};
463
464class Memory : public Node
465{
466 public:
467 /*
468 * Default Constructor
469 */
470 Memory(CrowApp &app) :
471 Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
472 std::string())
473 {
474
475 Node::json["@odata.type"] = "#Memory.v1_2_0.Memory";
476 Node::json["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
477 entityPrivileges = {
478 {boost::beast::http::verb::get, {{"Login"}}},
479 {boost::beast::http::verb::head, {{"Login"}}},
480 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
481 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
482 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
483 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
484 }
485
486 private:
487 /**
488 * Functions triggers appropriate requests on DBus
489 */
490 void doGet(crow::Response &res, const crow::Request &req,
491 const std::vector<std::string> &params) override
492 {
493 // Check if there is required param, truly entering this shall be
494 // impossible
495 if (params.size() != 2)
496 {
497 messages::internalError(res);
498 res.end();
499 return;
500 }
501 const std::string &name = params[0];
502 const std::string &dimmId = params[1];
503
504 res.jsonValue = Node::json;
505 res.jsonValue["@odata.id"] =
506 "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
507 auto asyncResp = std::make_shared<AsyncResp>(res);
508
509 getDimmData(asyncResp, name, dimmId);
510 }
511};
512
513} // namespace redfish