blob: 4426402c1fc0fd9d28c428cf4db791b91c2152ef [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",
151 "/xyz/openbmc_project/Intrusion", int32_t(1),
152 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
Gunnar Mills603a6642019-01-21 17:03:51 -0600185 const std::array<const char *, 3> interfaces = {
186 "xyz.openbmc_project.Inventory.Item.Board",
187 "xyz.openbmc_project.Inventory.Item.Chassis",
188 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
189
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700190 auto asyncResp = std::make_shared<AsyncResp>(res);
191 crow::connections::systemBus->async_method_call(
192 [asyncResp](const boost::system::error_code ec,
193 const std::vector<std::string> &chassisList) {
194 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700196 messages::internalError(asyncResp->res);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700197 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700198 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700199 nlohmann::json &chassisArray =
200 asyncResp->res.jsonValue["Members"];
201 chassisArray = nlohmann::json::array();
202 for (const std::string &objpath : chassisList)
203 {
204 std::size_t lastPos = objpath.rfind("/");
205 if (lastPos == std::string::npos)
206 {
207 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
208 continue;
209 }
210 chassisArray.push_back(
211 {{"@odata.id", "/redfish/v1/Chassis/" +
212 objpath.substr(lastPos + 1)}});
213 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100214
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700215 asyncResp->res.jsonValue["Members@odata.count"] =
216 chassisArray.size();
217 },
218 "xyz.openbmc_project.ObjectMapper",
219 "/xyz/openbmc_project/object_mapper",
220 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600221 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700222 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100223};
224
225/**
226 * Chassis override class for delivering Chassis Schema
227 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228class Chassis : public Node
229{
230 public:
231 Chassis(CrowApp &app) :
232 Node(app, "/redfish/v1/Chassis/<str>/", std::string())
233 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 entityPrivileges = {
235 {boost::beast::http::verb::get, {{"Login"}}},
236 {boost::beast::http::verb::head, {{"Login"}}},
237 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
238 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
239 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
240 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100241 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100242
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 private:
244 /**
245 * Functions triggers appropriate requests on DBus
246 */
247 void doGet(crow::Response &res, const crow::Request &req,
248 const std::vector<std::string> &params) override
249 {
Gunnar Mills734bfe92019-01-21 16:33:50 -0600250 const std::array<const char *, 3> interfaces = {
251 "xyz.openbmc_project.Inventory.Item.Board",
252 "xyz.openbmc_project.Inventory.Item.Chassis",
253 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
254
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 // Check if there is required param, truly entering this shall be
256 // impossible.
257 if (params.size() != 1)
258 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700259 messages::internalError(res);
Ed Tanousdaf36e22018-04-20 16:01:36 -0700260 res.end();
261 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 }
Shawn McCarney99cffd72019-03-01 10:46:20 -0600263 const std::string &chassisId = params[0];
Ed Tanouse0d918b2018-03-27 17:41:04 -0700264
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700265 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700267 [asyncResp, chassisId(std::string(chassisId))](
268 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269 const std::vector<std::pair<
270 std::string, std::vector<std::pair<
271 std::string, std::vector<std::string>>>>>
272 &subtree) {
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700273 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700275 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 return;
277 }
278 // Iterate over all retrieved ObjectPaths.
279 for (const std::pair<
280 std::string,
281 std::vector<
282 std::pair<std::string, std::vector<std::string>>>>
283 &object : subtree)
284 {
285 const std::string &path = object.first;
286 const std::vector<
287 std::pair<std::string, std::vector<std::string>>>
288 &connectionNames = object.second;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700289
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 if (!boost::ends_with(path, chassisId))
291 {
292 continue;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700293 }
Shawn McCarney26f03892019-05-03 13:20:24 -0500294
James Feistb49ac872019-05-21 15:12:01 -0700295 auto health = std::make_shared<HealthPopulate>(asyncResp);
296
297 crow::connections::systemBus->async_method_call(
298 [health](const boost::system::error_code ec,
299 std::variant<std::vector<std::string>> &resp) {
300 if (ec)
301 {
302 return; // no sensors = no failures
303 }
304 std::vector<std::string> *data =
305 std::get_if<std::vector<std::string>>(&resp);
306 if (data == nullptr)
307 {
308 return;
309 }
310 health->inventory = std::move(*data);
311 },
312 "xyz.openbmc_project.ObjectMapper",
313 path + "/all_sensors",
314 "org.freedesktop.DBus.Properties", "Get",
315 "xyz.openbmc_project.Association", "endpoints");
316
317 health->populate();
318
Ed Tanous1abe55e2018-09-05 08:30:59 -0700319 if (connectionNames.size() < 1)
320 {
321 BMCWEB_LOG_ERROR << "Only got "
322 << connectionNames.size()
323 << " Connection names";
324 continue;
325 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700326
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700327 asyncResp->res.jsonValue["@odata.type"] =
328 "#Chassis.v1_4_0.Chassis";
329 asyncResp->res.jsonValue["@odata.id"] =
330 "/redfish/v1/Chassis/" + chassisId;
331 asyncResp->res.jsonValue["@odata.context"] =
332 "/redfish/v1/$metadata#Chassis.Chassis";
333 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
334 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
335
336 const std::string &connectionName =
337 connectionNames[0].first;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700339 [asyncResp, chassisId(std::string(chassisId))](
340 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341 const std::vector<std::pair<
342 std::string, VariantType>> &propertiesList) {
343 for (const std::pair<std::string, VariantType>
344 &property : propertiesList)
345 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600346 // Store DBus properties that are also Redfish
347 // properties with same name and a string value
348 const std::string &propertyName =
349 property.first;
350 if ((propertyName == "PartNumber") ||
351 (propertyName == "SerialNumber") ||
352 (propertyName == "Manufacturer") ||
353 (propertyName == "Model"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700354 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600355 const std::string *value =
356 std::get_if<std::string>(
357 &property.second);
358 if (value != nullptr)
359 {
360 asyncResp->res.jsonValue[propertyName] =
361 *value;
362 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700363 }
364 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700365 asyncResp->res.jsonValue["Name"] = chassisId;
366 asyncResp->res.jsonValue["Id"] = chassisId;
367 asyncResp->res.jsonValue["Thermal"] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700368 {"@odata.id", "/redfish/v1/Chassis/" +
369 chassisId + "/Thermal"}};
Ed Tanous2474adf2018-09-05 16:31:16 -0700370 // Power object
371 asyncResp->res.jsonValue["Power"] = {
372 {"@odata.id", "/redfish/v1/Chassis/" +
373 chassisId + "/Power"}};
Ed Tanous029573d2019-02-01 10:57:49 -0800374 asyncResp->res.jsonValue["Status"] = {
Ed Tanous029573d2019-02-01 10:57:49 -0800375 {"State", "Enabled"},
376 };
Ed Tanous2474adf2018-09-05 16:31:16 -0700377
Ed Tanous029573d2019-02-01 10:57:49 -0800378 asyncResp->res
379 .jsonValue["Links"]["ComputerSystems"] = {
380 {{"@odata.id", "/redfish/v1/Systems/system"}}};
381 asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
382 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600383 getChassisState(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 },
385 connectionName, path, "org.freedesktop.DBus.Properties",
386 "GetAll",
387 "xyz.openbmc_project.Inventory.Decorator.Asset");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700388 return;
389 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700390
Ed Tanous1abe55e2018-09-05 08:30:59 -0700391 // Couldn't find an object with that name. return an error
Jason M. Billsf12894f2018-10-09 12:45:45 -0700392 messages::resourceNotFound(
393 asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 },
395 "xyz.openbmc_project.ObjectMapper",
396 "/xyz/openbmc_project/object_mapper",
397 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600398 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Qiang XUc1819422019-02-27 13:51:32 +0800399
400 getPhysicalSecurityData(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700402};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700403} // namespace redfish