blob: f1c3d9222fc48a65e994bcd6b45182d628ac989e [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
18#include <error_messages.hpp>
19#include <utils/json_utils.hpp>
20#include "node.hpp"
21#include "boost/container/flat_map.hpp"
22
23namespace redfish {
24
25/**
26 * SystemAsyncResp
27 * Gathers data needed for response processing after async calls are done
28 */
29class SystemAsyncResp {
30 public:
Ed Tanous55c7b7a2018-05-22 15:27:24 -070031 SystemAsyncResp(crow::Response &response) : res(response) {}
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020032
33 ~SystemAsyncResp() {
34 if (res.result() != (boost::beast::http::status::ok)) {
35 // Reset the json object to clear out any data that made it in before the
36 // error happened
37 // todo(ed) handle error condition with proper code
Ed Tanous55c7b7a2018-05-22 15:27:24 -070038 res.jsonValue = messages::internalError();
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020039 }
40 res.end();
41 }
42
43 void setErrorStatus() {
44 res.result(boost::beast::http::status::internal_server_error);
45 }
46
Ed Tanous55c7b7a2018-05-22 15:27:24 -070047 crow::Response &res;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020048};
49
50/**
51 * OnDemandSystemsProvider
52 * Board provider class that retrieves data directly from dbus, before seting
53 * it into JSON output. This does not cache any data.
54 *
55 * Class can be a good example on how to scale different data providing
56 * solutions to produce single schema output.
57 *
58 * TODO(Pawel)
59 * This perhaps shall be different file, which has to be chosen on compile time
60 * depending on OEM needs
61 */
62class OnDemandSystemsProvider {
63 public:
64 template <typename CallbackFunc>
65 void getBaseboardList(CallbackFunc &&callback) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070066 BMCWEB_LOG_DEBUG << "Get list of available boards.";
67 crow::connections::systemBus->async_method_call(
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020068 [callback{std::move(callback)}](const boost::system::error_code ec,
69 const std::vector<std::string> &resp) {
70 // Callback requires vector<string> to retrieve all available board
71 // list.
72 std::vector<std::string> board_list;
73 if (ec) {
74 // Something wrong on DBus, the error_code is not important at this
75 // moment, just return success=false, and empty output. Since size
76 // of vector may vary depending on information from Entity Manager,
77 // and empty output could not be treated same way as error.
78 callback(false, board_list);
79 return;
80 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070081 BMCWEB_LOG_DEBUG << "Got " << resp.size() << " boards.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +020082 // Iterate over all retrieved ObjectPaths.
83 for (const std::string &objpath : resp) {
84 std::size_t last_pos = objpath.rfind("/");
85 if (last_pos != std::string::npos) {
86 board_list.emplace_back(objpath.substr(last_pos + 1));
87 }
88 }
89 // Finally make a callback with useful data
90 callback(true, board_list);
91 },
92 "xyz.openbmc_project.ObjectMapper",
93 "/xyz/openbmc_project/object_mapper",
94 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
95 "/xyz/openbmc_project/inventory", int32_t(0),
96 std::array<const char *, 1>{
97 "xyz.openbmc_project.Inventory.Item.Board"});
98 };
99
100 /**
101 * @brief Retrieves computer system properties over dbus
102 *
103 * @param[in] aResp Shared pointer for completing asynchronous calls
104 * @param[in] name Computer system name from request
105 *
106 * @return None.
107 */
108 void getComputerSystem(std::shared_ptr<SystemAsyncResp> aResp,
109 const std::string &name) {
110 const std::array<const char *, 5> interfaces = {
111 "xyz.openbmc_project.Inventory.Decorator.Asset",
112 "xyz.openbmc_project.Inventory.Item.Cpu",
113 "xyz.openbmc_project.Inventory.Item.Dimm",
114 "xyz.openbmc_project.Inventory.Item.System",
115 "xyz.openbmc_project.Common.UUID",
116 };
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700117 BMCWEB_LOG_DEBUG << "Get available system components.";
118 crow::connections::systemBus->async_method_call(
Ed Tanous8ceb2ec2018-08-13 11:11:56 -0700119 [ name, aResp{std::move(aResp)} ](
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200120 const boost::system::error_code ec,
121 const std::vector<std::pair<
122 std::string,
123 std::vector<std::pair<std::string, std::vector<std::string>>>>>
124 &subtree) {
125 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700126 BMCWEB_LOG_DEBUG << "DBUS response error";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200127 aResp->setErrorStatus();
128 return;
129 }
130 bool foundName = false;
131 // Iterate over all retrieved ObjectPaths.
132 for (const std::pair<std::string,
133 std::vector<std::pair<std::string,
134 std::vector<std::string>>>>
135 &object : subtree) {
136 const std::string &path = object.first;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700137 BMCWEB_LOG_DEBUG << "Got path: " << path;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200138 const std::vector<std::pair<std::string, std::vector<std::string>>>
139 &connectionNames = object.second;
140 if (connectionNames.size() < 1) {
141 continue;
142 }
143 // Check if computer system exist
144 if (boost::ends_with(path, name)) {
145 foundName = true;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700146 BMCWEB_LOG_DEBUG << "Found name: " << name;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200147 const std::string connectionName = connectionNames[0].first;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700148 crow::connections::systemBus->async_method_call(
Ed Tanous8ceb2ec2018-08-13 11:11:56 -0700149 [ aResp, name(std::string(name)) ](
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200150 const boost::system::error_code ec,
151 const std::vector<std::pair<std::string, VariantType>>
152 &propertiesList) {
153 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700154 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200155 aResp->setErrorStatus();
156 return;
157 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700158 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
Ed Tanousa434f2b2018-07-27 13:04:22 -0700159 << "properties for system";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200160 for (const std::pair<std::string, VariantType> &property :
161 propertiesList) {
162 const std::string *value =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700163 mapbox::getPtr<const std::string>(property.second);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200164 if (value != nullptr) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700165 aResp->res.jsonValue[property.first] = *value;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200166 }
167 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700168 aResp->res.jsonValue["Name"] = name;
169 aResp->res.jsonValue["Id"] =
170 aResp->res.jsonValue["SerialNumber"];
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200171 },
172 connectionName, path, "org.freedesktop.DBus.Properties",
173 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
174 } else {
175 // This is not system, so check if it's cpu, dimm, UUID or BiosVer
176 for (auto const &s : connectionNames) {
177 for (auto const &i : s.second) {
178 if (boost::ends_with(i, "Dimm")) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700179 BMCWEB_LOG_DEBUG << "Found Dimm, now get it properties.";
180 crow::connections::systemBus->async_method_call(
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200181 [&, aResp](const boost::system::error_code ec,
182 const std::vector<std::pair<
183 std::string, VariantType>> &properties) {
184 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700185 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200186 aResp->setErrorStatus();
187 return;
188 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700189 BMCWEB_LOG_DEBUG << "Got " << properties.size()
Ed Tanousa434f2b2018-07-27 13:04:22 -0700190 << "Dimm properties.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200191 for (const auto &p : properties) {
192 if (p.first == "MemorySize") {
193 const std::string *value =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700194 mapbox::getPtr<const std::string>(p.second);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200195 if ((value != nullptr) && (*value != "NULL")) {
196 // Remove units char
197 int32_t unitCoeff;
198 if (boost::ends_with(*value, "MB")) {
199 unitCoeff = 1000;
200 } else if (boost::ends_with(*value, "KB")) {
201 unitCoeff = 1000000;
202 } else {
Ed Tanousa434f2b2018-07-27 13:04:22 -0700203 BMCWEB_LOG_ERROR
204 << "Unsupported memory units";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200205 aResp->setErrorStatus();
206 return;
207 }
208
209 auto memSize = boost::lexical_cast<int>(
210 value->substr(0, value->length() - 2));
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700211 aResp->res.jsonValue["TotalSystemMemoryGiB"] +=
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200212 memSize * unitCoeff;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700213 aResp->res.jsonValue["MemorySummary"]["Status"]
Ed Tanousa434f2b2018-07-27 13:04:22 -0700214 ["State"] = "Enabled";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200215 }
216 }
217 }
218 },
219 s.first, path, "org.freedesktop.DBus.Properties",
220 "GetAll", "xyz.openbmc_project.Inventory.Item.Dimm");
221 } else if (boost::ends_with(i, "Cpu")) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700222 BMCWEB_LOG_DEBUG << "Found Cpu, now get it properties.";
223 crow::connections::systemBus->async_method_call(
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200224 [&, aResp](const boost::system::error_code ec,
225 const std::vector<std::pair<
226 std::string, VariantType>> &properties) {
227 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700228 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200229 aResp->setErrorStatus();
230 return;
231 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700232 BMCWEB_LOG_DEBUG << "Got " << properties.size()
Ed Tanousa434f2b2018-07-27 13:04:22 -0700233 << "Cpu properties.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200234 for (const auto &p : properties) {
235 if (p.first == "ProcessorFamily") {
236 const std::string *value =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700237 mapbox::getPtr<const std::string>(p.second);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200238 if (value != nullptr) {
239 aResp->res
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700240 .jsonValue["ProcessorSummary"]["Count"] =
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200241 aResp->res
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700242 .jsonValue["ProcessorSummary"]["Count"]
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200243 .get<int>() +
244 1;
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700245 aResp->res.jsonValue["ProcessorSummary"]
Ed Tanousa434f2b2018-07-27 13:04:22 -0700246 ["Status"]["State"] =
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200247 "Enabled";
248 aResp->res
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700249 .jsonValue["ProcessorSummary"]["Model"] =
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200250 *value;
251 }
252 }
253 }
254 },
255 s.first, path, "org.freedesktop.DBus.Properties",
256 "GetAll", "xyz.openbmc_project.Inventory.Item.Cpu");
257 } else if (boost::ends_with(i, "UUID")) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700258 BMCWEB_LOG_DEBUG << "Found UUID, now get it properties.";
259 crow::connections::systemBus->async_method_call(
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200260 [aResp](const boost::system::error_code ec,
261 const std::vector<std::pair<
262 std::string, VariantType>> &properties) {
263 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700264 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200265 aResp->setErrorStatus();
266 return;
267 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700268 BMCWEB_LOG_DEBUG << "Got " << properties.size()
Ed Tanousa434f2b2018-07-27 13:04:22 -0700269 << "UUID properties.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200270 for (const std::pair<std::string, VariantType> &p :
271 properties) {
272 if (p.first == "BIOSVer") {
273 const std::string *value =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700274 mapbox::getPtr<const std::string>(p.second);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200275 if (value != nullptr) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700276 aResp->res.jsonValue["BiosVersion"] = *value;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200277 }
278 }
279 if (p.first == "UUID") {
280 const std::string *value =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700281 mapbox::getPtr<const std::string>(p.second);
282 BMCWEB_LOG_DEBUG << "UUID = " << *value
Ed Tanousa434f2b2018-07-27 13:04:22 -0700283 << " length " << value->length();
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200284 if (value != nullptr) {
285 // Workaround for to short return str in smbios
286 // demo app, 32 bytes are described by spec
287 if (value->length() > 0 &&
288 value->length() < 32) {
289 std::string correctedValue = *value;
290 correctedValue.append(32 - value->length(),
291 '0');
292 value = &correctedValue;
293 } else if (value->length() == 32) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700294 aResp->res.jsonValue["UUID"] =
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200295 value->substr(0, 8) + "-" +
296 value->substr(8, 4) + "-" +
297 value->substr(12, 4) + "-" +
298 value->substr(16, 4) + "-" +
299 value->substr(20, 12);
300 }
301 }
302 }
303 }
304 },
305 s.first, path, "org.freedesktop.DBus.Properties",
306 "GetAll", "xyz.openbmc_project.Common.UUID");
307 }
308 }
309 }
310 }
311 }
312 if (foundName == false) {
313 aResp->setErrorStatus();
314 }
315 },
316 "xyz.openbmc_project.ObjectMapper",
317 "/xyz/openbmc_project/object_mapper",
318 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
319 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
320 }
321
322 /**
323 * @brief Retrieves identify led group properties over dbus
324 *
325 * @param[in] aResp Shared pointer for completing asynchronous calls.
326 * @param[in] callback Callback for process retrieved data.
327 *
328 * @return None.
329 */
330 template <typename CallbackFunc>
331 void getLedGroupIdentify(std::shared_ptr<SystemAsyncResp> aResp,
332 CallbackFunc &&callback) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700333 BMCWEB_LOG_DEBUG << "Get led groups";
334 crow::connections::systemBus->async_method_call(
Ed Tanous8ceb2ec2018-08-13 11:11:56 -0700335 [
336 aResp{std::move(aResp)}, &callback
337 ](const boost::system::error_code &ec, const ManagedObjectsType &resp) {
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200338 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700339 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200340 aResp->setErrorStatus();
341 return;
342 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700343 BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200344 for (const auto &objPath : resp) {
345 const std::string &path = objPath.first;
346 if (path.rfind("enclosure_identify") != std::string::npos) {
347 for (const auto &interface : objPath.second) {
348 if (interface.first == "xyz.openbmc_project.Led.Group") {
349 for (const auto &property : interface.second) {
350 if (property.first == "Asserted") {
351 const bool *asserted =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700352 mapbox::getPtr<const bool>(property.second);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200353 if (nullptr != asserted) {
354 callback(*asserted, aResp);
355 } else {
356 callback(false, aResp);
357 }
358 }
359 }
360 }
361 }
362 }
363 }
364 },
365 "xyz.openbmc_project.LED.GroupManager",
366 "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager",
367 "GetManagedObjects");
368 }
369
370 template <typename CallbackFunc>
371 void getLedIdentify(std::shared_ptr<SystemAsyncResp> aResp,
372 CallbackFunc &&callback) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700373 BMCWEB_LOG_DEBUG << "Get identify led properties";
374 crow::connections::systemBus->async_method_call(
Ed Tanous8ceb2ec2018-08-13 11:11:56 -0700375 [ aResp{std::move(aResp)}, &callback ](
376 const boost::system::error_code ec,
377 const PropertiesType &properties) {
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200378 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700379 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200380 aResp->setErrorStatus();
381 return;
382 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700383 BMCWEB_LOG_DEBUG << "Got " << properties.size() << "led properties.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200384 std::string output;
385 for (const auto &property : properties) {
386 if (property.first == "State") {
387 const std::string *s =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700388 mapbox::getPtr<std::string>(property.second);
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200389 if (nullptr != s) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700390 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200391 const auto pos = s->rfind('.');
392 if (pos != std::string::npos) {
393 auto led = s->substr(pos + 1);
394 for (const std::pair<const char *, const char *> &p :
395 std::array<std::pair<const char *, const char *>, 3>{
396 {{"On", "Lit"},
397 {"Blink", "Blinking"},
398 {"Off", "Off"}}}) {
399 if (led == p.first) {
400 output = p.second;
401 }
402 }
403 }
404 }
405 }
406 }
407 callback(output, aResp);
408 },
409 "xyz.openbmc_project.LED.Controller.identify",
410 "/xyz/openbmc_project/led/physical/identify",
411 "org.freedesktop.DBus.Properties", "GetAll",
412 "xyz.openbmc_project.Led.Physical");
413 }
414
415 /**
416 * @brief Retrieves host state properties over dbus
417 *
418 * @param[in] aResp Shared pointer for completing asynchronous calls.
419 *
420 * @return None.
421 */
422 void getHostState(std::shared_ptr<SystemAsyncResp> aResp) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700423 BMCWEB_LOG_DEBUG << "Get host information.";
424 crow::connections::systemBus->async_method_call(
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200425 [aResp{std::move(aResp)}](const boost::system::error_code ec,
426 const PropertiesType &properties) {
427 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700428 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200429 aResp->setErrorStatus();
430 return;
431 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700432 BMCWEB_LOG_DEBUG << "Got " << properties.size() << "host properties.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200433 for (const auto &property : properties) {
434 if (property.first == "CurrentHostState") {
435 const std::string *s =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700436 mapbox::getPtr<const std::string>(property.second);
437 BMCWEB_LOG_DEBUG << "Host state: " << *s;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200438 if (nullptr != s) {
439 const auto pos = s->rfind('.');
440 if (pos != std::string::npos) {
441 // Verify Host State
442 if (s->substr(pos + 1) == "Running") {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700443 aResp->res.jsonValue["PowerState"] = "On";
444 aResp->res.jsonValue["Status"]["State"] = "Enabled";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200445 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700446 aResp->res.jsonValue["PowerState"] = "Off";
447 aResp->res.jsonValue["Status"]["State"] = "Disabled";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200448 }
449 }
450 }
451 }
452 }
453 },
454 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
455 "org.freedesktop.DBus.Properties", "GetAll",
456 "xyz.openbmc_project.State.Host");
457 }
458};
459
460/**
461 * SystemsCollection derived class for delivering ComputerSystems Collection
462 * Schema
463 */
464class SystemsCollection : public Node {
465 public:
466 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") {
467 Node::json["@odata.type"] =
468 "#ComputerSystemCollection.ComputerSystemCollection";
469 Node::json["@odata.id"] = "/redfish/v1/Systems";
470 Node::json["@odata.context"] =
471 "/redfish/v1/"
472 "$metadata#ComputerSystemCollection.ComputerSystemCollection";
473 Node::json["Name"] = "Computer System Collection";
474
475 entityPrivileges = {
476 {boost::beast::http::verb::get, {{"Login"}}},
477 {boost::beast::http::verb::head, {{"Login"}}},
478 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
479 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
480 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
481 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
482 }
483
484 private:
485 /**
486 * Functions triggers appropriate requests on DBus
487 */
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700488 void doGet(crow::Response &res, const crow::Request &req,
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200489 const std::vector<std::string> &params) override {
490 // Get board list, and call the below callback for JSON preparation
491 provider.getBaseboardList(
492 [&](const bool &success, const std::vector<std::string> &output) {
493 if (success) {
494 // ... prepare json array with appropriate @odata.id links
495 nlohmann::json boardArray = nlohmann::json::array();
496 for (const std::string &board_item : output) {
497 boardArray.push_back(
498 {{"@odata.id", "/redfish/v1/Systems/" + board_item}});
499 }
500 // Then attach members, count size and return,
501 Node::json["Members"] = boardArray;
502 Node::json["Members@odata.count"] = boardArray.size();
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700503 res.jsonValue = Node::json;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200504 } else {
505 // ... otherwise, return INTERNALL ERROR
506 res.result(boost::beast::http::status::internal_server_error);
507 }
508 res.end();
509 });
510 }
511
512 OnDemandSystemsProvider provider;
513};
514
515/**
516 * Systems override class for delivering ComputerSystems Schema
517 */
518class Systems : public Node {
519 public:
520 /*
521 * Default Constructor
522 */
523 Systems(CrowApp &app)
524 : Node(app, "/redfish/v1/Systems/<str>/", std::string()) {
525 Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
526 Node::json["@odata.context"] =
527 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
528 Node::json["SystemType"] = "Physical";
529 Node::json["Description"] = "Computer System";
530 Node::json["Boot"]["BootSourceOverrideEnabled"] =
531 "Disabled"; // TODO(Dawid), get real boot data
532 Node::json["Boot"]["BootSourceOverrideTarget"] =
533 "None"; // TODO(Dawid), get real boot data
534 Node::json["Boot"]["BootSourceOverrideMode"] =
535 "Legacy"; // TODO(Dawid), get real boot data
536 Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] = {
537 "None", "Pxe", "Hdd", "Cd",
538 "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot data
539 Node::json["ProcessorSummary"]["Count"] = int(0);
540 Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled";
541 Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
542 Node::json["MemorySummary"]["Status"]["State"] = "Disabled";
543
544 entityPrivileges = {
545 {boost::beast::http::verb::get, {{"Login"}}},
546 {boost::beast::http::verb::head, {{"Login"}}},
547 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
548 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
549 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
550 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
551 }
552
553 private:
554 OnDemandSystemsProvider provider;
555
556 /**
557 * Functions triggers appropriate requests on DBus
558 */
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700559 void doGet(crow::Response &res, const crow::Request &req,
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200560 const std::vector<std::string> &params) override {
561 // Check if there is required param, truly entering this shall be
562 // impossible
563 if (params.size() != 1) {
564 res.result(boost::beast::http::status::internal_server_error);
565 res.end();
566 return;
567 }
568
569 const std::string &name = params[0];
570
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700571 res.jsonValue = Node::json;
572 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200573
574 auto asyncResp = std::make_shared<SystemAsyncResp>(res);
575
576 provider.getLedGroupIdentify(
577 asyncResp, [&](const bool &asserted,
578 const std::shared_ptr<SystemAsyncResp> &aResp) {
579 if (asserted) {
580 // If led group is asserted, then another call is needed to
581 // get led status
582 provider.getLedIdentify(
583 aResp, [](const std::string &ledStatus,
584 const std::shared_ptr<SystemAsyncResp> &aResp) {
585 if (!ledStatus.empty()) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700586 aResp->res.jsonValue["IndicatorLED"] = ledStatus;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200587 }
588 });
589 } else {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700590 aResp->res.jsonValue["IndicatorLED"] = "Off";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200591 }
592 });
593 provider.getComputerSystem(asyncResp, name);
594 provider.getHostState(asyncResp);
595 }
596
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700597 void doPatch(crow::Response &res, const crow::Request &req,
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200598 const std::vector<std::string> &params) override {
599 // Check if there is required param, truly entering this shall be
600 // impossible
601 if (params.size() != 1) {
602 res.result(boost::beast::http::status::internal_server_error);
603 res.end();
604 return;
605 }
606 // Parse JSON request body
607 nlohmann::json patch;
608 if (!json_util::processJsonFromRequest(res, req, patch)) {
609 return;
610 }
611 // Find key with new led value
612 const std::string &name = params[0];
613 const std::string *reqLedState = nullptr;
614 json_util::Result r = json_util::getString(
615 "IndicatorLED", patch, reqLedState,
616 static_cast<int>(json_util::MessageSetting::TYPE_ERROR) |
617 static_cast<int>(json_util::MessageSetting::MISSING),
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700618 res.jsonValue, std::string("/" + name + "/IndicatorLED"));
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200619 if ((r != json_util::Result::SUCCESS) || (reqLedState == nullptr)) {
620 res.result(boost::beast::http::status::bad_request);
621 res.end();
622 return;
623 }
624 // Verify key value
625 std::string dbusLedState;
626 for (const auto &p : boost::container::flat_map<const char *, const char *>{
627 {"On", "Lit"}, {"Blink", "Blinking"}, {"Off", "Off"}}) {
628 if (*reqLedState == p.second) {
629 dbusLedState = p.first;
630 }
631 }
632
633 // Update led status
634 auto asyncResp = std::make_shared<SystemAsyncResp>(res);
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700635 res.jsonValue = Node::json;
636 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200637
638 provider.getHostState(asyncResp);
639 provider.getComputerSystem(asyncResp, name);
640
641 if (dbusLedState.empty()) {
642 messages::addMessageToJsonRoot(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700643 res.jsonValue,
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200644 messages::propertyValueNotInList(*reqLedState, "IndicatorLED"));
645 } else {
646 // Update led group
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700647 BMCWEB_LOG_DEBUG << "Update led group.";
648 crow::connections::systemBus->async_method_call(
Ed Tanous8ceb2ec2018-08-13 11:11:56 -0700649 [&, asyncResp{std::move(asyncResp)} ](
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200650 const boost::system::error_code ec) {
651 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700652 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200653 asyncResp->setErrorStatus();
654 return;
655 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700656 BMCWEB_LOG_DEBUG << "Led group update done.";
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200657 },
658 "xyz.openbmc_project.LED.GroupManager",
659 "/xyz/openbmc_project/led/groups/enclosure_identify",
660 "org.freedesktop.DBus.Properties", "Set",
661 "xyz.openbmc_project.Led.Group", "Asserted",
662 sdbusplus::message::variant<bool>(
663 (dbusLedState == "Off" ? false : true)));
664 // Update identify led status
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700665 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
666 crow::connections::systemBus->async_method_call(
Ed Tanous8ceb2ec2018-08-13 11:11:56 -0700667 [&, asyncResp{std::move(asyncResp)} ](
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200668 const boost::system::error_code ec) {
669 if (ec) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700670 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200671 asyncResp->setErrorStatus();
672 return;
673 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700674 BMCWEB_LOG_DEBUG << "Led state update done.";
675 res.jsonValue["IndicatorLED"] = *reqLedState;
Lewanczyk, Dawidc5b2abe2018-05-30 16:59:42 +0200676 },
677 "xyz.openbmc_project.LED.Controller.identify",
678 "/xyz/openbmc_project/led/physical/identify",
679 "org.freedesktop.DBus.Properties", "Set",
680 "xyz.openbmc_project.Led.Physical", "State",
681 sdbusplus::message::variant<std::string>(
682 "xyz.openbmc_project.Led.Physical.Action." + dbusLedState));
683 }
684 }
685};
686} // namespace redfish