blob: d8bc8f5d531c9b805434a46ce0cb4b1b838806e6 [file] [log] [blame]
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +01001/*
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
James Feistb49ac872019-05-21 15:12:01 -070018#include "health.hpp"
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010019#include "node.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070020
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010021#include <boost/container/flat_map.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080022#include <variant>
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010023
Ed Tanous1abe55e2018-09-05 08:30:59 -070024namespace redfish
25{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010026
27/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060028 * @brief Retrieves chassis state properties over dbus
29 *
30 * @param[in] aResp - Shared pointer for completing asynchronous calls.
31 *
32 * @return None.
33 */
34void getChassisState(std::shared_ptr<AsyncResp> aResp)
35{
36 crow::connections::systemBus->async_method_call(
37 [aResp{std::move(aResp)}](
38 const boost::system::error_code ec,
39 const std::variant<std::string> &chassisState) {
40 if (ec)
41 {
42 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
43 messages::internalError(aResp->res);
44 return;
45 }
46
47 const std::string *s = std::get_if<std::string>(&chassisState);
48 BMCWEB_LOG_DEBUG << "Chassis state: " << *s;
49 if (s != nullptr)
50 {
51 // Verify Chassis State
52 if (*s == "xyz.openbmc_project.State.Chassis.PowerState.On")
53 {
54 aResp->res.jsonValue["PowerState"] = "On";
55 aResp->res.jsonValue["Status"]["State"] = "Enabled";
56 }
57 else if (*s ==
58 "xyz.openbmc_project.State.Chassis.PowerState.Off")
59 {
60 aResp->res.jsonValue["PowerState"] = "Off";
61 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
62 }
63 }
64 },
65 "xyz.openbmc_project.State.Chassis",
66 "/xyz/openbmc_project/state/chassis0",
67 "org.freedesktop.DBus.Properties", "Get",
68 "xyz.openbmc_project.State.Chassis", "CurrentPowerState");
69}
70
71/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010072 * DBus types primitives for several generic DBus interfaces
73 * TODO(Pawel) consider move this to separate file into boost::dbus
74 */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070075// Note, this is not a very useful Variant, but because it isn't used to get
Ed Tanousaa2e59c2018-04-12 12:17:20 -070076// values, it should be as simple as possible
77// TODO(ed) invent a nullvariant type
Ed Tanousabf2add2019-01-22 16:40:12 -080078using VariantType = std::variant<bool, std::string, uint64_t>;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070079using ManagedObjectsType = std::vector<std::pair<
80 sdbusplus::message::object_path,
81 std::vector<std::pair<std::string,
82 std::vector<std::pair<std::string, VariantType>>>>>>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010083
Ed Tanousaa2e59c2018-04-12 12:17:20 -070084using PropertiesType = boost::container::flat_map<std::string, VariantType>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010085
Qiang XUc1819422019-02-27 13:51:32 +080086void getIntrusionByService(std::shared_ptr<AsyncResp> aResp,
87 const std::string &service,
88 const std::string &objPath)
89{
90 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
91
92 crow::connections::systemBus->async_method_call(
93 [aResp{std::move(aResp)}](const boost::system::error_code ec,
94 const std::variant<std::string> &value) {
95 if (ec)
96 {
97 // do not add err msg in redfish response, becaues this is not
98 // mandatory property
99 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
100 return;
101 }
102
103 const std::string *status = std::get_if<std::string>(&value);
104
105 if (status == nullptr)
106 {
107 BMCWEB_LOG_ERROR << "intrusion status read error \n";
108 return;
109 }
110
111 aResp->res.jsonValue["PhysicalSecurity"] = {
112 {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}};
113 },
114 service, objPath, "org.freedesktop.DBus.Properties", "Get",
115 "xyz.openbmc_project.Chassis.Intrusion", "Status");
116}
117
118/**
119 * Retrieves physical security properties over dbus
120 */
121void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp)
122{
123 crow::connections::systemBus->async_method_call(
124 [aResp{std::move(aResp)}](
125 const boost::system::error_code ec,
126 const std::vector<std::pair<
127 std::string,
128 std::vector<std::pair<std::string, std::vector<std::string>>>>>
129 &subtree) {
130 if (ec)
131 {
132 // do not add err msg in redfish response, becaues this is not
133 // mandatory property
134 BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec
135 << "\n";
136 return;
137 }
138 // Iterate over all retrieved ObjectPaths.
139 for (const auto &object : subtree)
140 {
141 for (const auto &service : object.second)
142 {
143 getIntrusionByService(aResp, service.first, object.first);
144 return;
145 }
146 }
147 },
148 "xyz.openbmc_project.ObjectMapper",
149 "/xyz/openbmc_project/object_mapper",
150 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Ed Tanous271584a2019-07-09 16:24:22 -0700151 "/xyz/openbmc_project/Intrusion", 1,
Qiang XUc1819422019-02-27 13:51:32 +0800152 std::array<const char *, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
153}
154
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100155/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100156 * ChassisCollection derived class for delivering Chassis Collection Schema
157 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700158class ChassisCollection : public Node
159{
160 public:
161 ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
162 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700163 entityPrivileges = {
164 {boost::beast::http::verb::get, {{"Login"}}},
165 {boost::beast::http::verb::head, {{"Login"}}},
166 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
167 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
168 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
169 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
170 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100171
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 private:
173 /**
174 * Functions triggers appropriate requests on DBus
175 */
176 void doGet(crow::Response &res, const crow::Request &req,
177 const std::vector<std::string> &params) override
178 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800179 res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
180 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
181 res.jsonValue["@odata.context"] =
182 "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
183 res.jsonValue["Name"] = "Chassis Collection";
184
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500185 const std::array<const char *, 2> interfaces = {
Gunnar Mills603a6642019-01-21 17:03:51 -0600186 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500187 "xyz.openbmc_project.Inventory.Item.Chassis"};
Gunnar Mills603a6642019-01-21 17:03:51 -0600188
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700189 auto asyncResp = std::make_shared<AsyncResp>(res);
190 crow::connections::systemBus->async_method_call(
191 [asyncResp](const boost::system::error_code ec,
192 const std::vector<std::string> &chassisList) {
193 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700195 messages::internalError(asyncResp->res);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700196 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700198 nlohmann::json &chassisArray =
199 asyncResp->res.jsonValue["Members"];
200 chassisArray = nlohmann::json::array();
201 for (const std::string &objpath : chassisList)
202 {
203 std::size_t lastPos = objpath.rfind("/");
204 if (lastPos == std::string::npos)
205 {
206 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
207 continue;
208 }
209 chassisArray.push_back(
210 {{"@odata.id", "/redfish/v1/Chassis/" +
211 objpath.substr(lastPos + 1)}});
212 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100213
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700214 asyncResp->res.jsonValue["Members@odata.count"] =
215 chassisArray.size();
216 },
217 "xyz.openbmc_project.ObjectMapper",
218 "/xyz/openbmc_project/object_mapper",
219 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Ed Tanous271584a2019-07-09 16:24:22 -0700220 "/xyz/openbmc_project/inventory", 0, interfaces);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700221 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100222};
223
224/**
225 * Chassis override class for delivering Chassis Schema
226 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227class Chassis : public Node
228{
229 public:
230 Chassis(CrowApp &app) :
231 Node(app, "/redfish/v1/Chassis/<str>/", std::string())
232 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233 entityPrivileges = {
234 {boost::beast::http::verb::get, {{"Login"}}},
235 {boost::beast::http::verb::head, {{"Login"}}},
236 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
237 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
238 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
239 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100240 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100241
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242 private:
243 /**
244 * Functions triggers appropriate requests on DBus
245 */
246 void doGet(crow::Response &res, const crow::Request &req,
247 const std::vector<std::string> &params) override
248 {
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500249 const std::array<const char *, 2> interfaces = {
Gunnar Mills734bfe92019-01-21 16:33:50 -0600250 "xyz.openbmc_project.Inventory.Item.Board",
Shawn McCarneyadc4f0d2019-07-24 09:21:50 -0500251 "xyz.openbmc_project.Inventory.Item.Chassis"};
Gunnar Mills734bfe92019-01-21 16:33:50 -0600252
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 // Check if there is required param, truly entering this shall be
254 // impossible.
255 if (params.size() != 1)
256 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700257 messages::internalError(res);
Ed Tanousdaf36e22018-04-20 16:01:36 -0700258 res.end();
259 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260 }
Shawn McCarney99cffd72019-03-01 10:46:20 -0600261 const std::string &chassisId = params[0];
Ed Tanouse0d918b2018-03-27 17:41:04 -0700262
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700263 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700265 [asyncResp, chassisId(std::string(chassisId))](
266 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700267 const std::vector<std::pair<
268 std::string, std::vector<std::pair<
269 std::string, std::vector<std::string>>>>>
270 &subtree) {
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700271 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700273 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 return;
275 }
276 // Iterate over all retrieved ObjectPaths.
277 for (const std::pair<
278 std::string,
279 std::vector<
280 std::pair<std::string, std::vector<std::string>>>>
281 &object : subtree)
282 {
283 const std::string &path = object.first;
284 const std::vector<
285 std::pair<std::string, std::vector<std::string>>>
286 &connectionNames = object.second;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700287
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 if (!boost::ends_with(path, chassisId))
289 {
290 continue;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700291 }
Shawn McCarney26f03892019-05-03 13:20:24 -0500292
James Feistb49ac872019-05-21 15:12:01 -0700293 auto health = std::make_shared<HealthPopulate>(asyncResp);
294
295 crow::connections::systemBus->async_method_call(
296 [health](const boost::system::error_code ec,
297 std::variant<std::vector<std::string>> &resp) {
298 if (ec)
299 {
300 return; // no sensors = no failures
301 }
302 std::vector<std::string> *data =
303 std::get_if<std::vector<std::string>>(&resp);
304 if (data == nullptr)
305 {
306 return;
307 }
308 health->inventory = std::move(*data);
309 },
310 "xyz.openbmc_project.ObjectMapper",
311 path + "/all_sensors",
312 "org.freedesktop.DBus.Properties", "Get",
313 "xyz.openbmc_project.Association", "endpoints");
314
315 health->populate();
316
Ed Tanous1abe55e2018-09-05 08:30:59 -0700317 if (connectionNames.size() < 1)
318 {
319 BMCWEB_LOG_ERROR << "Only got "
320 << connectionNames.size()
321 << " Connection names";
322 continue;
323 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700324
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700325 asyncResp->res.jsonValue["@odata.type"] =
Jason M. Billsadbe1922019-10-14 15:44:35 -0700326 "#Chassis.v1_10_0.Chassis";
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700327 asyncResp->res.jsonValue["@odata.id"] =
328 "/redfish/v1/Chassis/" + chassisId;
329 asyncResp->res.jsonValue["@odata.context"] =
330 "/redfish/v1/$metadata#Chassis.Chassis";
331 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
332 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
Jason M. Billsadbe1922019-10-14 15:44:35 -0700333 asyncResp->res.jsonValue["PCIeDevices"] = {
334 {"@odata.id",
335 "/redfish/v1/Systems/system/PCIeDevices"}};
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700336
337 const std::string &connectionName =
338 connectionNames[0].first;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700340 [asyncResp, chassisId(std::string(chassisId))](
341 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700342 const std::vector<std::pair<
343 std::string, VariantType>> &propertiesList) {
344 for (const std::pair<std::string, VariantType>
345 &property : propertiesList)
346 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600347 // Store DBus properties that are also Redfish
348 // properties with same name and a string value
349 const std::string &propertyName =
350 property.first;
351 if ((propertyName == "PartNumber") ||
352 (propertyName == "SerialNumber") ||
353 (propertyName == "Manufacturer") ||
354 (propertyName == "Model"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600356 const std::string *value =
357 std::get_if<std::string>(
358 &property.second);
359 if (value != nullptr)
360 {
361 asyncResp->res.jsonValue[propertyName] =
362 *value;
363 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364 }
365 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700366 asyncResp->res.jsonValue["Name"] = chassisId;
367 asyncResp->res.jsonValue["Id"] = chassisId;
368 asyncResp->res.jsonValue["Thermal"] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700369 {"@odata.id", "/redfish/v1/Chassis/" +
370 chassisId + "/Thermal"}};
Ed Tanous2474adf2018-09-05 16:31:16 -0700371 // Power object
372 asyncResp->res.jsonValue["Power"] = {
373 {"@odata.id", "/redfish/v1/Chassis/" +
374 chassisId + "/Power"}};
Anthony Wilson95a3eca2019-06-11 10:44:47 -0500375 // SensorCollection
376 asyncResp->res.jsonValue["Sensors"] = {
377 {"@odata.id", "/redfish/v1/Chassis/" +
378 chassisId + "/Sensors"}};
Ed Tanous029573d2019-02-01 10:57:49 -0800379 asyncResp->res.jsonValue["Status"] = {
Ed Tanous029573d2019-02-01 10:57:49 -0800380 {"State", "Enabled"},
381 };
Ed Tanous2474adf2018-09-05 16:31:16 -0700382
Ed Tanous029573d2019-02-01 10:57:49 -0800383 asyncResp->res
384 .jsonValue["Links"]["ComputerSystems"] = {
385 {{"@odata.id", "/redfish/v1/Systems/system"}}};
386 asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
387 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600388 getChassisState(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 },
390 connectionName, path, "org.freedesktop.DBus.Properties",
391 "GetAll",
392 "xyz.openbmc_project.Inventory.Decorator.Asset");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700393 return;
394 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700395
Ed Tanous1abe55e2018-09-05 08:30:59 -0700396 // Couldn't find an object with that name. return an error
Jason M. Billsf12894f2018-10-09 12:45:45 -0700397 messages::resourceNotFound(
Jason M. Billsadbe1922019-10-14 15:44:35 -0700398 asyncResp->res, "#Chassis.v1_10_0.Chassis", chassisId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399 },
400 "xyz.openbmc_project.ObjectMapper",
401 "/xyz/openbmc_project/object_mapper",
402 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Ed Tanous271584a2019-07-09 16:24:22 -0700403 "/xyz/openbmc_project/inventory", 0, interfaces);
Qiang XUc1819422019-02-27 13:51:32 +0800404
405 getPhysicalSecurityData(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700407};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700408} // namespace redfish