blob: 40624110550e694bea84ababaad2dc2e2eb95614 [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");
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600219 if (memorySizeProperty != properties.end())
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200220 {
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600221 const uint32_t *memorySize =
222 sdbusplus::message::variant_ns::get_if<uint32_t>(
223 &memorySizeProperty->second);
224 if (memorySize == nullptr)
225 {
226 // Important property not in desired type
227 messages::internalError(aResp->res);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200228
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600229 return;
230 }
231 if (*memorySize == 0)
232 {
233 // Slot is not populated, set status end return
234 aResp->res.jsonValue["Status"]["State"] = "Absent";
235 aResp->res.jsonValue["Status"]["Health"] = "OK";
236 // HTTP Code will be set up automatically, just return
237 return;
238 }
239 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200240 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200241 aResp->res.jsonValue["Status"]["State"] = "Enabled";
242 aResp->res.jsonValue["Status"]["Health"] = "OK";
243
244 for (const auto &property : properties)
245 {
246 if (property.first == "MemoryDataWidth")
247 {
248 aResp->res.jsonValue["DataWidthBits"] = property.second;
249 }
250 else if (property.first == "MemoryType")
251 {
252 const auto *value =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800253 sdbusplus::message::variant_ns::get_if<std::string>(
254 &property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200255 if (value != nullptr)
256 {
257 aResp->res.jsonValue["MemoryDeviceType"] = *value;
258 if (boost::starts_with(*value, "DDR"))
259 {
260 aResp->res.jsonValue["MemoryType"] = "DRAM";
261 }
262 }
263 }
264 }
265 },
266 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
267}
268
269void getDimmData(std::shared_ptr<AsyncResp> aResp, const std::string &name,
270 const std::string &dimmId)
271{
272 BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
273 crow::connections::systemBus->async_method_call(
274 [name, dimmId, aResp{std::move(aResp)}](
275 const boost::system::error_code ec,
276 const boost::container::flat_map<
277 std::string, boost::container::flat_map<
278 std::string, std::vector<std::string>>>
279 &subtree) {
280 if (ec)
281 {
282 BMCWEB_LOG_DEBUG << "DBUS response error";
283 messages::internalError(aResp->res);
284
285 return;
286 }
287 for (const auto &object : subtree)
288 {
289 if (boost::ends_with(object.first, dimmId))
290 {
291 for (const auto &service : object.second)
292 {
293 getDimmDataByService(aResp, name, dimmId, service.first,
294 object.first);
295 return;
296 }
297 }
298 }
299 // Object not found
300 messages::resourceNotFound(aResp->res, "Memory", dimmId);
301 return;
302 },
303 "xyz.openbmc_project.ObjectMapper",
304 "/xyz/openbmc_project/object_mapper",
305 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
306 "/xyz/openbmc_project/inventory", int32_t(0),
307 std::array<const char *, 1>{"xyz.openbmc_project.Inventory.Item.Dimm"});
308};
309
310class ProcessorCollection : public Node
311{
312 public:
313 /*
314 * Default Constructor
315 */
316 ProcessorCollection(CrowApp &app) :
317 Node(app, "/redfish/v1/Systems/<str>/Processors/", std::string())
318 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200319 entityPrivileges = {
320 {boost::beast::http::verb::get, {{"Login"}}},
321 {boost::beast::http::verb::head, {{"Login"}}},
322 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
323 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
324 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
325 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
326 }
327
328 private:
329 /**
330 * Functions triggers appropriate requests on DBus
331 */
332 void doGet(crow::Response &res, const crow::Request &req,
333 const std::vector<std::string> &params) override
334 {
335 // Check if there is required param, truly entering this shall be
336 // impossible
337 if (params.size() != 1)
338 {
339 messages::internalError(res);
340 res.end();
341 return;
342 }
343 const std::string &name = params[0];
344
Ed Tanous0f74e642018-11-12 15:17:05 -0800345 res.jsonValue["@odata.type"] =
346 "#ProcessorCollection.ProcessorCollection";
347 res.jsonValue["Name"] = "Processor Collection";
348 res.jsonValue["@odata.context"] =
349 "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
350
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200351 res.jsonValue["@odata.id"] =
352 "/redfish/v1/Systems/" + name + "/Processors/";
353 auto asyncResp = std::make_shared<AsyncResp>(res);
354
355 getResourceList(asyncResp, name, "Processors",
356 "xyz.openbmc_project.Inventory.Item.Cpu");
357 }
358};
359
360class Processor : public Node
361{
362 public:
363 /*
364 * Default Constructor
365 */
366 Processor(CrowApp &app) :
367 Node(app, "/redfish/v1/Systems/<str>/Processors/<str>/", std::string(),
368 std::string())
369 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200370 entityPrivileges = {
371 {boost::beast::http::verb::get, {{"Login"}}},
372 {boost::beast::http::verb::head, {{"Login"}}},
373 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
374 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
375 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
376 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
377 }
378
379 private:
380 /**
381 * Functions triggers appropriate requests on DBus
382 */
383 void doGet(crow::Response &res, const crow::Request &req,
384 const std::vector<std::string> &params) override
385 {
386 // Check if there is required param, truly entering this shall be
387 // impossible
388 if (params.size() != 2)
389 {
390 messages::internalError(res);
391
392 res.end();
393 return;
394 }
395 const std::string &name = params[0];
396 const std::string &cpuId = params[1];
Rapkiewicz, Pawelbb3d9942018-11-22 10:59:11 +0100397 res.jsonValue["@odata.type"] = "#Processor.v1_3_1.Processor";
Ed Tanous0f74e642018-11-12 15:17:05 -0800398 res.jsonValue["@odata.context"] =
399 "/redfish/v1/$metadata#Processor.Processor";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200400 res.jsonValue["@odata.id"] =
401 "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
402
403 auto asyncResp = std::make_shared<AsyncResp>(res);
404
405 getCpuData(asyncResp, name, cpuId);
406 }
407};
408
409class MemoryCollection : public Node
410{
411 public:
412 /*
413 * Default Constructor
414 */
415 MemoryCollection(CrowApp &app) :
416 Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
417 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200418 entityPrivileges = {
419 {boost::beast::http::verb::get, {{"Login"}}},
420 {boost::beast::http::verb::head, {{"Login"}}},
421 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
422 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
423 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
424 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
425 }
426
427 private:
428 /**
429 * Functions triggers appropriate requests on DBus
430 */
431 void doGet(crow::Response &res, const crow::Request &req,
432 const std::vector<std::string> &params) override
433 {
434 // Check if there is required param, truly entering this shall be
435 // impossible
436 if (params.size() != 1)
437 {
438 messages::internalError(res);
439
440 res.end();
441 return;
442 }
443 const std::string &name = params[0];
444
Ed Tanous0f74e642018-11-12 15:17:05 -0800445 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
446 res.jsonValue["Name"] = "Memory Module Collection";
447 res.jsonValue["@odata.context"] =
448 "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200449 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
450 auto asyncResp = std::make_shared<AsyncResp>(res);
451
452 getResourceList(asyncResp, name, "Memory",
453 "xyz.openbmc_project.Inventory.Item.Dimm");
454 }
455};
456
457class Memory : public Node
458{
459 public:
460 /*
461 * Default Constructor
462 */
463 Memory(CrowApp &app) :
464 Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
465 std::string())
466 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200467 entityPrivileges = {
468 {boost::beast::http::verb::get, {{"Login"}}},
469 {boost::beast::http::verb::head, {{"Login"}}},
470 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
471 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
472 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
473 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
474 }
475
476 private:
477 /**
478 * Functions triggers appropriate requests on DBus
479 */
480 void doGet(crow::Response &res, const crow::Request &req,
481 const std::vector<std::string> &params) override
482 {
483 // Check if there is required param, truly entering this shall be
484 // impossible
485 if (params.size() != 2)
486 {
487 messages::internalError(res);
488 res.end();
489 return;
490 }
491 const std::string &name = params[0];
492 const std::string &dimmId = params[1];
493
Rapkiewicz, Pawelbb3d9942018-11-22 10:59:11 +0100494 res.jsonValue["@odata.type"] = "#Memory.v1_6_0.Memory";
Ed Tanous0f74e642018-11-12 15:17:05 -0800495 res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200496 res.jsonValue["@odata.id"] =
497 "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
498 auto asyncResp = std::make_shared<AsyncResp>(res);
499
500 getDimmData(asyncResp, name, dimmId);
501 }
502};
503
504} // namespace redfish