blob: 229ec0be53ccf0c766dcae75af095c16ad7b1fb6 [file] [log] [blame]
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +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
Ed Tanous1abe55e2018-09-05 08:30:59 -070018#include "boost/container/flat_map.hpp"
19#include "node.hpp"
20
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020021#include <error_messages.hpp>
22#include <utils/json_utils.hpp>
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020023
Ed Tanous1abe55e2018-09-05 08:30:59 -070024namespace redfish
25{
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020026
27/**
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020028 * OnDemandSystemsProvider
29 * Board provider class that retrieves data directly from dbus, before seting
30 * it into JSON output. This does not cache any data.
31 *
32 * Class can be a good example on how to scale different data providing
33 * solutions to produce single schema output.
34 *
35 * TODO(Pawel)
36 * This perhaps shall be different file, which has to be chosen on compile time
37 * depending on OEM needs
38 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070039class OnDemandSystemsProvider
40{
41 public:
42 template <typename CallbackFunc>
43 void getBaseboardList(CallbackFunc &&callback)
44 {
45 BMCWEB_LOG_DEBUG << "Get list of available boards.";
46 crow::connections::systemBus->async_method_call(
47 [callback{std::move(callback)}](
48 const boost::system::error_code ec,
49 const std::vector<std::string> &resp) {
50 // Callback requires vector<string> to retrieve all available
51 // board list.
52 std::vector<std::string> boardList;
53 if (ec)
54 {
55 // Something wrong on DBus, the error_code is not important
56 // at this moment, just return success=false, and empty
57 // output. Since size of vector may vary depending on
58 // information from Entity Manager, and empty output could
59 // not be treated same way as error.
60 callback(false, boardList);
61 return;
62 }
63 BMCWEB_LOG_DEBUG << "Got " << resp.size() << " boards.";
64 // Iterate over all retrieved ObjectPaths.
65 for (const std::string &objpath : resp)
66 {
67 std::size_t lastPos = objpath.rfind("/");
68 if (lastPos != std::string::npos)
69 {
70 boardList.emplace_back(objpath.substr(lastPos + 1));
71 }
72 }
73 // Finally make a callback with useful data
74 callback(true, boardList);
75 },
76 "xyz.openbmc_project.ObjectMapper",
77 "/xyz/openbmc_project/object_mapper",
78 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
79 "/xyz/openbmc_project/inventory", int32_t(0),
80 std::array<const char *, 1>{
81 "xyz.openbmc_project.Inventory.Item.Board"});
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020082 };
Ed Tanous1abe55e2018-09-05 08:30:59 -070083
84 /**
85 * @brief Retrieves computer system properties over dbus
86 *
87 * @param[in] aResp Shared pointer for completing asynchronous calls
88 * @param[in] name Computer system name from request
89 *
90 * @return None.
91 */
Ed Tanousa0803ef2018-08-29 13:29:23 -070092 void getComputerSystem(std::shared_ptr<AsyncResp> aResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 const std::string &name)
94 {
95 const std::array<const char *, 5> interfaces = {
96 "xyz.openbmc_project.Inventory.Decorator.Asset",
97 "xyz.openbmc_project.Inventory.Item.Cpu",
98 "xyz.openbmc_project.Inventory.Item.Dimm",
99 "xyz.openbmc_project.Inventory.Item.System",
100 "xyz.openbmc_project.Common.UUID",
101 };
102 BMCWEB_LOG_DEBUG << "Get available system components.";
103 crow::connections::systemBus->async_method_call(
104 [name, aResp{std::move(aResp)}](
105 const boost::system::error_code ec,
106 const std::vector<std::pair<
107 std::string, std::vector<std::pair<
108 std::string, std::vector<std::string>>>>>
109 &subtree) {
110 if (ec)
111 {
112 BMCWEB_LOG_DEBUG << "DBUS response error";
Ed Tanousa0803ef2018-08-29 13:29:23 -0700113 aResp->res.result(
114 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 return;
116 }
117 bool foundName = false;
118 // Iterate over all retrieved ObjectPaths.
119 for (const std::pair<
120 std::string,
121 std::vector<
122 std::pair<std::string, std::vector<std::string>>>>
123 &object : subtree)
124 {
125 const std::string &path = object.first;
126 BMCWEB_LOG_DEBUG << "Got path: " << path;
127 const std::vector<
128 std::pair<std::string, std::vector<std::string>>>
129 &connectionNames = object.second;
130 if (connectionNames.size() < 1)
131 {
132 continue;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200133 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 // Check if computer system exist
135 if (boost::ends_with(path, name))
136 {
137 foundName = true;
138 BMCWEB_LOG_DEBUG << "Found name: " << name;
139 const std::string connectionName =
140 connectionNames[0].first;
141 crow::connections::systemBus->async_method_call(
142 [aResp, name(std::string(name))](
143 const boost::system::error_code ec,
144 const std::vector<
145 std::pair<std::string, VariantType>>
146 &propertiesList) {
147 if (ec)
148 {
149 BMCWEB_LOG_ERROR << "DBUS response error: "
150 << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700151 aResp->res.result(
152 boost::beast::http::status::
153 internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700154 return;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200155 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 BMCWEB_LOG_DEBUG << "Got "
157 << propertiesList.size()
158 << "properties for system";
159 for (const std::pair<std::string, VariantType>
160 &property : propertiesList)
161 {
162 const std::string *value =
163 mapbox::getPtr<const std::string>(
164 property.second);
165 if (value != nullptr)
166 {
167 aResp->res.jsonValue[property.first] =
168 *value;
169 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200170 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 aResp->res.jsonValue["Name"] = name;
172 aResp->res.jsonValue["Id"] =
173 aResp->res.jsonValue["SerialNumber"];
174 },
175 connectionName, path,
176 "org.freedesktop.DBus.Properties", "GetAll",
177 "xyz.openbmc_project.Inventory.Decorator.Asset");
178 }
179 else
180 {
181 // This is not system, so check if it's cpu, dimm, UUID
182 // or BiosVer
183 for (auto const &s : connectionNames)
184 {
185 for (auto const &i : s.second)
186 {
187 if (boost::ends_with(i, "Dimm"))
188 {
189 BMCWEB_LOG_DEBUG
190 << "Found Dimm, now get it properties.";
191 crow::connections::systemBus->async_method_call(
192 [&, aResp](
193 const boost::system::error_code ec,
194 const std::vector<std::pair<
195 std::string, VariantType>>
196 &properties) {
197 if (ec)
198 {
199 BMCWEB_LOG_ERROR
200 << "DBUS response error "
201 << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700202 aResp->res.result(
203 boost::beast::http::status::
204 internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700205 return;
206 }
207 BMCWEB_LOG_DEBUG
208 << "Got " << properties.size()
209 << "Dimm properties.";
210 for (const auto &p : properties)
211 {
212 if (p.first == "MemorySize")
213 {
214 const std::string *value =
215 mapbox::getPtr<
216 const std::string>(
217 p.second);
218 if ((value != nullptr) &&
219 (*value != "NULL"))
220 {
221 // Remove units char
222 int32_t unitCoeff;
223 if (boost::ends_with(
224 *value, "MB"))
225 {
226 unitCoeff = 1000;
227 }
228 else if (boost::
229 ends_with(
230 *value,
231 "KB"))
232 {
233 unitCoeff = 1000000;
234 }
235 else
236 {
237 BMCWEB_LOG_ERROR
238 << "Unsupported"
239 " memory "
240 "units";
Ed Tanousa0803ef2018-08-29 13:29:23 -0700241 aResp->res.result(
242 boost::beast::
243 http::status::
244 internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245 return;
246 }
247
248 auto memSize =
249 boost::lexical_cast<
250 int>(value->substr(
251 0,
252 value->length() -
253 2));
254 aResp->res.jsonValue
255 ["TotalSystemMemory"
256 "GiB"] +=
257 memSize * unitCoeff;
258 aResp->res.jsonValue
259 ["MemorySummary"]
260 ["Status"]
261 ["State"] =
262 "Enabled";
263 }
264 }
265 }
266 },
267 s.first, path,
268 "org.freedesktop.DBus.Properties",
269 "GetAll",
270 "xyz.openbmc_project.Inventory.Item."
271 "Dimm");
272 }
273 else if (boost::ends_with(i, "Cpu"))
274 {
275 BMCWEB_LOG_DEBUG
276 << "Found Cpu, now get it properties.";
Ed Tanousa0803ef2018-08-29 13:29:23 -0700277 crow::connections::systemBus->async_method_call(
278 [&, aResp](
279 const boost::system::error_code ec,
280 const std::vector<std::pair<
281 std::string, VariantType>>
282 &properties) {
283 if (ec)
284 {
285 BMCWEB_LOG_ERROR
286 << "DBUS response error "
287 << ec;
288 aResp->res.result(
289 boost::beast::http::status::
290 internal_server_error);
291 return;
292 }
293 BMCWEB_LOG_DEBUG
294 << "Got " << properties.size()
295 << "Cpu properties.";
296 for (const auto &p : properties)
297 {
298 if (p.first ==
299 "ProcessorFamily")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 {
Ed Tanousa0803ef2018-08-29 13:29:23 -0700301 const std::string *value =
302 mapbox::getPtr<
303 const std::string>(
304 p.second);
305 if (value != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 {
Ed Tanousa0803ef2018-08-29 13:29:23 -0700307 aResp->res.jsonValue
308 ["ProcessorSummary"]
309 ["Count"] =
310 aResp->res
311 .jsonValue
312 ["Processor"
313 "Summary"]
314 ["Count"]
315 .get<int>() +
316 1;
317 aResp->res.jsonValue
318 ["ProcessorSummary"]
319 ["Status"]
320 ["State"] =
321 "Enabled";
322 aResp->res.jsonValue
323 ["ProcessorSummary"]
324 ["Model"] = *value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 }
326 }
Ed Tanousa0803ef2018-08-29 13:29:23 -0700327 }
328 },
329 s.first, path,
330 "org.freedesktop.DBus.Properties",
331 "GetAll",
332 "xyz.openbmc_project.Inventory.Item."
333 "Cpu");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700334 }
335 else if (boost::ends_with(i, "UUID"))
336 {
337 BMCWEB_LOG_DEBUG
338 << "Found UUID, now get it properties.";
339 crow::connections::systemBus->async_method_call(
340 [aResp](
341 const boost::system::error_code ec,
342 const std::vector<std::pair<
343 std::string, VariantType>>
344 &properties) {
345 if (ec)
346 {
347 BMCWEB_LOG_DEBUG
348 << "DBUS response error "
349 << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700350 aResp->res.result(
351 boost::beast::http::status::
352 internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353 return;
354 }
355 BMCWEB_LOG_DEBUG
356 << "Got " << properties.size()
357 << "UUID properties.";
358 for (const std::pair<std::string,
359 VariantType>
360 &p : properties)
361 {
362 if (p.first == "BIOSVer")
363 {
364 const std::string *value =
365 mapbox::getPtr<
366 const std::string>(
367 p.second);
368 if (value != nullptr)
369 {
370 aResp->res.jsonValue
371 ["BiosVersion"] =
372 *value;
373 }
374 }
375 if (p.first == "UUID")
376 {
377 const std::string *value =
378 mapbox::getPtr<
379 const std::string>(
380 p.second);
381 BMCWEB_LOG_DEBUG
382 << "UUID = " << *value
383 << " length "
384 << value->length();
385 if (value != nullptr)
386 {
387 // Workaround for to
388 // short return str in
389 // smbios demo app, 32
390 // bytes are described
391 // by spec
392 if (value->length() >
393 0 &&
394 value->length() <
395 32)
396 {
397 std::string
398 correctedValue =
399 *value;
400 correctedValue.append(
401 32 -
402 value
403 ->length(),
404 '0');
405 value =
406 &correctedValue;
407 }
408 else if (
409 value->length() ==
410 32)
411 {
412 aResp->res.jsonValue
413 ["UUID"] =
414 value->substr(
415 0, 8) +
416 "-" +
417 value->substr(
418 8, 4) +
419 "-" +
420 value->substr(
421 12, 4) +
422 "-" +
423 value->substr(
424 16, 4) +
425 "-" +
426 value->substr(
427 20, 12);
428 }
429 }
430 }
431 }
432 },
433 s.first, path,
434 "org.freedesktop.DBus.Properties",
435 "GetAll",
436 "xyz.openbmc_project.Common.UUID");
437 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200438 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200440 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200441 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700442 if (foundName == false)
443 {
Ed Tanousa0803ef2018-08-29 13:29:23 -0700444 aResp->res.result(
445 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700446 }
447 },
448 "xyz.openbmc_project.ObjectMapper",
449 "/xyz/openbmc_project/object_mapper",
450 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
451 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
452 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200453
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 /**
455 * @brief Retrieves identify led group properties over dbus
456 *
457 * @param[in] aResp Shared pointer for completing asynchronous calls.
458 * @param[in] callback Callback for process retrieved data.
459 *
460 * @return None.
461 */
462 template <typename CallbackFunc>
Ed Tanousa0803ef2018-08-29 13:29:23 -0700463 void getLedGroupIdentify(std::shared_ptr<AsyncResp> aResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 CallbackFunc &&callback)
465 {
466 BMCWEB_LOG_DEBUG << "Get led groups";
467 crow::connections::systemBus->async_method_call(
468 [aResp{std::move(aResp)},
469 &callback](const boost::system::error_code &ec,
470 const ManagedObjectsType &resp) {
471 if (ec)
472 {
473 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700474 aResp->res.result(
475 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 return;
477 }
478 BMCWEB_LOG_DEBUG << "Got " << resp.size()
479 << "led group objects.";
480 for (const auto &objPath : resp)
481 {
482 const std::string &path = objPath.first;
483 if (path.rfind("enclosure_identify") != std::string::npos)
484 {
485 for (const auto &interface : objPath.second)
486 {
487 if (interface.first ==
488 "xyz.openbmc_project.Led.Group")
489 {
490 for (const auto &property : interface.second)
491 {
492 if (property.first == "Asserted")
493 {
494 const bool *asserted =
495 mapbox::getPtr<const bool>(
496 property.second);
497 if (nullptr != asserted)
498 {
499 callback(*asserted, aResp);
500 }
501 else
502 {
503 callback(false, aResp);
504 }
505 }
506 }
507 }
508 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200509 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200510 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 },
512 "xyz.openbmc_project.LED.GroupManager",
513 "/xyz/openbmc_project/led/groups",
514 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
515 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200516
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517 template <typename CallbackFunc>
Ed Tanousa0803ef2018-08-29 13:29:23 -0700518 void getLedIdentify(std::shared_ptr<AsyncResp> aResp,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 CallbackFunc &&callback)
520 {
521 BMCWEB_LOG_DEBUG << "Get identify led properties";
522 crow::connections::systemBus->async_method_call(
523 [aResp{std::move(aResp)},
524 &callback](const boost::system::error_code ec,
525 const PropertiesType &properties) {
526 if (ec)
527 {
528 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700529 aResp->res.result(
530 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 return;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200532 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 BMCWEB_LOG_DEBUG << "Got " << properties.size()
534 << "led properties.";
535 std::string output;
536 for (const auto &property : properties)
537 {
538 if (property.first == "State")
539 {
540 const std::string *s =
541 mapbox::getPtr<std::string>(property.second);
542 if (nullptr != s)
543 {
544 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
545 const auto pos = s->rfind('.');
546 if (pos != std::string::npos)
547 {
548 auto led = s->substr(pos + 1);
549 for (const std::pair<const char *, const char *>
550 &p :
551 std::array<
552 std::pair<const char *, const char *>,
553 3>{{{"On", "Lit"},
554 {"Blink", "Blinking"},
555 {"Off", "Off"}}})
556 {
557 if (led == p.first)
558 {
559 output = p.second;
560 }
561 }
562 }
563 }
564 }
565 }
566 callback(output, aResp);
567 },
568 "xyz.openbmc_project.LED.Controller.identify",
569 "/xyz/openbmc_project/led/physical/identify",
570 "org.freedesktop.DBus.Properties", "GetAll",
571 "xyz.openbmc_project.Led.Physical");
572 }
573
574 /**
575 * @brief Retrieves host state properties over dbus
576 *
577 * @param[in] aResp Shared pointer for completing asynchronous calls.
578 *
579 * @return None.
580 */
Ed Tanousa0803ef2018-08-29 13:29:23 -0700581 void getHostState(std::shared_ptr<AsyncResp> aResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 {
583 BMCWEB_LOG_DEBUG << "Get host information.";
584 crow::connections::systemBus->async_method_call(
585 [aResp{std::move(aResp)}](const boost::system::error_code ec,
586 const PropertiesType &properties) {
587 if (ec)
588 {
589 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700590 aResp->res.result(
591 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592 return;
593 }
594 BMCWEB_LOG_DEBUG << "Got " << properties.size()
595 << "host properties.";
596 for (const auto &property : properties)
597 {
598 if (property.first == "CurrentHostState")
599 {
600 const std::string *s =
601 mapbox::getPtr<const std::string>(property.second);
602 BMCWEB_LOG_DEBUG << "Host state: " << *s;
603 if (nullptr != s)
604 {
605 const auto pos = s->rfind('.');
606 if (pos != std::string::npos)
607 {
608 // Verify Host State
609 if (s->substr(pos + 1) == "Running")
610 {
611 aResp->res.jsonValue["PowerState"] = "On";
612 aResp->res.jsonValue["Status"]["State"] =
613 "Enabled";
614 }
615 else
616 {
617 aResp->res.jsonValue["PowerState"] = "Off";
618 aResp->res.jsonValue["Status"]["State"] =
619 "Disabled";
620 }
621 }
622 }
623 }
624 }
625 },
626 "xyz.openbmc_project.State.Host",
627 "/xyz/openbmc_project/state/host0",
628 "org.freedesktop.DBus.Properties", "GetAll",
629 "xyz.openbmc_project.State.Host");
630 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200631};
632
633/**
634 * SystemsCollection derived class for delivering ComputerSystems Collection
635 * Schema
636 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637class SystemsCollection : public Node
638{
639 public:
640 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
641 {
642 Node::json["@odata.type"] =
643 "#ComputerSystemCollection.ComputerSystemCollection";
644 Node::json["@odata.id"] = "/redfish/v1/Systems";
645 Node::json["@odata.context"] =
646 "/redfish/v1/"
647 "$metadata#ComputerSystemCollection.ComputerSystemCollection";
648 Node::json["Name"] = "Computer System Collection";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200649
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 entityPrivileges = {
651 {boost::beast::http::verb::get, {{"Login"}}},
652 {boost::beast::http::verb::head, {{"Login"}}},
653 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
654 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
655 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
656 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
657 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200658
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 private:
660 /**
661 * Functions triggers appropriate requests on DBus
662 */
663 void doGet(crow::Response &res, const crow::Request &req,
664 const std::vector<std::string> &params) override
665 {
666 // Get board list, and call the below callback for JSON preparation
667 provider.getBaseboardList([&](const bool &success,
668 const std::vector<std::string> &output) {
669 if (success)
670 {
671 // ... prepare json array with appropriate @odata.id links
672 nlohmann::json boardArray = nlohmann::json::array();
673 for (const std::string &boardItem : output)
674 {
675 boardArray.push_back(
676 {{"@odata.id", "/redfish/v1/Systems/" + boardItem}});
677 }
678 // Then attach members, count size and return,
679 Node::json["Members"] = boardArray;
680 Node::json["Members@odata.count"] = boardArray.size();
681 res.jsonValue = Node::json;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200682 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 else
684 {
685 // ... otherwise, return INTERNALL ERROR
686 res.result(boost::beast::http::status::internal_server_error);
687 }
688 res.end();
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200689 });
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200691
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 OnDemandSystemsProvider provider;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200693};
694
695/**
696 * Systems override class for delivering ComputerSystems Schema
697 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700698class Systems : public Node
699{
700 public:
701 /*
702 * Default Constructor
703 */
704 Systems(CrowApp &app) :
705 Node(app, "/redfish/v1/Systems/<str>/", std::string())
706 {
707 Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
708 Node::json["@odata.context"] =
709 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
710 Node::json["SystemType"] = "Physical";
711 Node::json["Description"] = "Computer System";
712 Node::json["Boot"]["BootSourceOverrideEnabled"] =
713 "Disabled"; // TODO(Dawid), get real boot data
714 Node::json["Boot"]["BootSourceOverrideTarget"] =
715 "None"; // TODO(Dawid), get real boot data
716 Node::json["Boot"]["BootSourceOverrideMode"] =
717 "Legacy"; // TODO(Dawid), get real boot data
718 Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] =
719 {"None", "Pxe", "Hdd", "Cd",
720 "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot
721 // data
722 Node::json["ProcessorSummary"]["Count"] = int(0);
723 Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled";
724 Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
725 Node::json["MemorySummary"]["Status"]["State"] = "Disabled";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200726
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 entityPrivileges = {
728 {boost::beast::http::verb::get, {{"Login"}}},
729 {boost::beast::http::verb::head, {{"Login"}}},
730 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
731 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
732 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
733 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200734 }
735
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 private:
737 OnDemandSystemsProvider provider;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200738
Ed Tanous1abe55e2018-09-05 08:30:59 -0700739 /**
740 * Functions triggers appropriate requests on DBus
741 */
742 void doGet(crow::Response &res, const crow::Request &req,
743 const std::vector<std::string> &params) override
744 {
745 // Check if there is required param, truly entering this shall be
746 // impossible
747 if (params.size() != 1)
748 {
749 res.result(boost::beast::http::status::internal_server_error);
750 res.end();
751 return;
752 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200753
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 const std::string &name = params[0];
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200755
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 res.jsonValue = Node::json;
757 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200758
Ed Tanousa0803ef2018-08-29 13:29:23 -0700759 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760
761 provider.getLedGroupIdentify(
Ed Tanousa0803ef2018-08-29 13:29:23 -0700762 asyncResp,
763 [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 if (asserted)
765 {
766 // If led group is asserted, then another call is needed to
767 // get led status
768 provider.getLedIdentify(
Ed Tanousa0803ef2018-08-29 13:29:23 -0700769 aResp, [](const std::string &ledStatus,
770 const std::shared_ptr<AsyncResp> &aResp) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 if (!ledStatus.empty())
772 {
773 aResp->res.jsonValue["IndicatorLED"] =
774 ledStatus;
775 }
776 });
777 }
778 else
779 {
780 aResp->res.jsonValue["IndicatorLED"] = "Off";
781 }
782 });
783 provider.getComputerSystem(asyncResp, name);
784 provider.getHostState(asyncResp);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200785 }
786
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 void doPatch(crow::Response &res, const crow::Request &req,
788 const std::vector<std::string> &params) override
789 {
790 // Check if there is required param, truly entering this shall be
791 // impossible
792 if (params.size() != 1)
793 {
794 res.result(boost::beast::http::status::internal_server_error);
795 res.end();
796 return;
797 }
798 // Parse JSON request body
799 nlohmann::json patch;
800 if (!json_util::processJsonFromRequest(res, req, patch))
801 {
802 return;
803 }
804 // Find key with new led value
805 const std::string &name = params[0];
806 const std::string *reqLedState = nullptr;
807 json_util::Result r = json_util::getString(
808 "IndicatorLED", patch, reqLedState,
809 static_cast<int>(json_util::MessageSetting::TYPE_ERROR) |
810 static_cast<int>(json_util::MessageSetting::MISSING),
811 res.jsonValue, std::string("/" + name + "/IndicatorLED"));
812 if ((r != json_util::Result::SUCCESS) || (reqLedState == nullptr))
813 {
814 res.result(boost::beast::http::status::bad_request);
815 res.end();
816 return;
817 }
818 // Verify key value
819 std::string dbusLedState;
820 for (const auto &p :
821 boost::container::flat_map<const char *, const char *>{
822 {"On", "Lit"}, {"Blink", "Blinking"}, {"Off", "Off"}})
823 {
824 if (*reqLedState == p.second)
825 {
826 dbusLedState = p.first;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200827 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 }
829
830 // Update led status
Ed Tanousa0803ef2018-08-29 13:29:23 -0700831 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 res.jsonValue = Node::json;
833 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
834
835 provider.getHostState(asyncResp);
836 provider.getComputerSystem(asyncResp, name);
837
838 if (dbusLedState.empty())
839 {
840 messages::addMessageToJsonRoot(
841 res.jsonValue,
842 messages::propertyValueNotInList(*reqLedState, "IndicatorLED"));
843 }
844 else
845 {
846 // Update led group
847 BMCWEB_LOG_DEBUG << "Update led group.";
848 crow::connections::systemBus->async_method_call(
849 [&, asyncResp{std::move(asyncResp)}](
850 const boost::system::error_code ec) {
851 if (ec)
852 {
853 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700854 asyncResp->res.result(
855 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 return;
857 }
858 BMCWEB_LOG_DEBUG << "Led group update done.";
859 },
860 "xyz.openbmc_project.LED.GroupManager",
861 "/xyz/openbmc_project/led/groups/enclosure_identify",
862 "org.freedesktop.DBus.Properties", "Set",
863 "xyz.openbmc_project.Led.Group", "Asserted",
864 sdbusplus::message::variant<bool>(
865 (dbusLedState == "Off" ? false : true)));
866 // Update identify led status
867 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
868 crow::connections::systemBus->async_method_call(
869 [&, asyncResp{std::move(asyncResp)}](
870 const boost::system::error_code ec) {
871 if (ec)
872 {
873 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Ed Tanousa0803ef2018-08-29 13:29:23 -0700874 asyncResp->res.result(
875 boost::beast::http::status::internal_server_error);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 return;
877 }
878 BMCWEB_LOG_DEBUG << "Led state update done.";
879 res.jsonValue["IndicatorLED"] = *reqLedState;
880 },
881 "xyz.openbmc_project.LED.Controller.identify",
882 "/xyz/openbmc_project/led/physical/identify",
883 "org.freedesktop.DBus.Properties", "Set",
884 "xyz.openbmc_project.Led.Physical", "State",
885 sdbusplus::message::variant<std::string>(
886 "xyz.openbmc_project.Led.Physical.Action." + dbusLedState));
887 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200888 }
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200889};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890} // namespace redfish