blob: 5cc453105542b61458756ac692caf8ee63340f87 [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
18#include "node.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070019
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010020#include <boost/container/flat_map.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080021#include <variant>
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023namespace redfish
24{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010025
26/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060027 * @brief Retrieves chassis state properties over dbus
28 *
29 * @param[in] aResp - Shared pointer for completing asynchronous calls.
30 *
31 * @return None.
32 */
33void getChassisState(std::shared_ptr<AsyncResp> aResp)
34{
35 crow::connections::systemBus->async_method_call(
36 [aResp{std::move(aResp)}](
37 const boost::system::error_code ec,
38 const std::variant<std::string> &chassisState) {
39 if (ec)
40 {
41 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
42 messages::internalError(aResp->res);
43 return;
44 }
45
46 const std::string *s = std::get_if<std::string>(&chassisState);
47 BMCWEB_LOG_DEBUG << "Chassis state: " << *s;
48 if (s != nullptr)
49 {
50 // Verify Chassis State
51 if (*s == "xyz.openbmc_project.State.Chassis.PowerState.On")
52 {
53 aResp->res.jsonValue["PowerState"] = "On";
54 aResp->res.jsonValue["Status"]["State"] = "Enabled";
55 }
56 else if (*s ==
57 "xyz.openbmc_project.State.Chassis.PowerState.Off")
58 {
59 aResp->res.jsonValue["PowerState"] = "Off";
60 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
61 }
62 }
63 },
64 "xyz.openbmc_project.State.Chassis",
65 "/xyz/openbmc_project/state/chassis0",
66 "org.freedesktop.DBus.Properties", "Get",
67 "xyz.openbmc_project.State.Chassis", "CurrentPowerState");
68}
69
70/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010071 * DBus types primitives for several generic DBus interfaces
72 * TODO(Pawel) consider move this to separate file into boost::dbus
73 */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070074// Note, this is not a very useful Variant, but because it isn't used to get
Ed Tanousaa2e59c2018-04-12 12:17:20 -070075// values, it should be as simple as possible
76// TODO(ed) invent a nullvariant type
Ed Tanousabf2add2019-01-22 16:40:12 -080077using VariantType = std::variant<bool, std::string, uint64_t>;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070078using ManagedObjectsType = std::vector<std::pair<
79 sdbusplus::message::object_path,
80 std::vector<std::pair<std::string,
81 std::vector<std::pair<std::string, VariantType>>>>>>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010082
Ed Tanousaa2e59c2018-04-12 12:17:20 -070083using PropertiesType = boost::container::flat_map<std::string, VariantType>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010084
Qiang XUc1819422019-02-27 13:51:32 +080085void getIntrusionByService(std::shared_ptr<AsyncResp> aResp,
86 const std::string &service,
87 const std::string &objPath)
88{
89 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
90
91 crow::connections::systemBus->async_method_call(
92 [aResp{std::move(aResp)}](const boost::system::error_code ec,
93 const std::variant<std::string> &value) {
94 if (ec)
95 {
96 // do not add err msg in redfish response, becaues this is not
97 // mandatory property
98 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
99 return;
100 }
101
102 const std::string *status = std::get_if<std::string>(&value);
103
104 if (status == nullptr)
105 {
106 BMCWEB_LOG_ERROR << "intrusion status read error \n";
107 return;
108 }
109
110 aResp->res.jsonValue["PhysicalSecurity"] = {
111 {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}};
112 },
113 service, objPath, "org.freedesktop.DBus.Properties", "Get",
114 "xyz.openbmc_project.Chassis.Intrusion", "Status");
115}
116
117/**
118 * Retrieves physical security properties over dbus
119 */
120void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp)
121{
122 crow::connections::systemBus->async_method_call(
123 [aResp{std::move(aResp)}](
124 const boost::system::error_code ec,
125 const std::vector<std::pair<
126 std::string,
127 std::vector<std::pair<std::string, std::vector<std::string>>>>>
128 &subtree) {
129 if (ec)
130 {
131 // do not add err msg in redfish response, becaues this is not
132 // mandatory property
133 BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec
134 << "\n";
135 return;
136 }
137 // Iterate over all retrieved ObjectPaths.
138 for (const auto &object : subtree)
139 {
140 for (const auto &service : object.second)
141 {
142 getIntrusionByService(aResp, service.first, object.first);
143 return;
144 }
145 }
146 },
147 "xyz.openbmc_project.ObjectMapper",
148 "/xyz/openbmc_project/object_mapper",
149 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
150 "/xyz/openbmc_project/Intrusion", int32_t(1),
151 std::array<const char *, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
152}
153
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100154/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100155 * ChassisCollection derived class for delivering Chassis Collection Schema
156 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700157class ChassisCollection : public Node
158{
159 public:
160 ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
161 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 entityPrivileges = {
163 {boost::beast::http::verb::get, {{"Login"}}},
164 {boost::beast::http::verb::head, {{"Login"}}},
165 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
166 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
167 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
168 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
169 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100170
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 private:
172 /**
173 * Functions triggers appropriate requests on DBus
174 */
175 void doGet(crow::Response &res, const crow::Request &req,
176 const std::vector<std::string> &params) override
177 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800178 res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
179 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
180 res.jsonValue["@odata.context"] =
181 "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
182 res.jsonValue["Name"] = "Chassis Collection";
183
Gunnar Mills603a6642019-01-21 17:03:51 -0600184#ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
185 // Assume one Chassis named "chassis"
186 res.jsonValue["Members@odata.count"] = 1;
187 res.jsonValue["Members"] = {
188 {{"@odata.id", "/redfish/v1/Chassis/chassis"}}};
189 res.end();
190 return;
191#endif
192 const std::array<const char *, 3> interfaces = {
193 "xyz.openbmc_project.Inventory.Item.Board",
194 "xyz.openbmc_project.Inventory.Item.Chassis",
195 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
196
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700197 auto asyncResp = std::make_shared<AsyncResp>(res);
198 crow::connections::systemBus->async_method_call(
199 [asyncResp](const boost::system::error_code ec,
200 const std::vector<std::string> &chassisList) {
201 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700202 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700203 messages::internalError(asyncResp->res);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700204 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700205 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700206 nlohmann::json &chassisArray =
207 asyncResp->res.jsonValue["Members"];
208 chassisArray = nlohmann::json::array();
209 for (const std::string &objpath : chassisList)
210 {
211 std::size_t lastPos = objpath.rfind("/");
212 if (lastPos == std::string::npos)
213 {
214 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
215 continue;
216 }
217 chassisArray.push_back(
218 {{"@odata.id", "/redfish/v1/Chassis/" +
219 objpath.substr(lastPos + 1)}});
220 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100221
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700222 asyncResp->res.jsonValue["Members@odata.count"] =
223 chassisArray.size();
224 },
225 "xyz.openbmc_project.ObjectMapper",
226 "/xyz/openbmc_project/object_mapper",
227 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600228 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700229 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100230};
231
232/**
233 * Chassis override class for delivering Chassis Schema
234 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700235class Chassis : public Node
236{
237 public:
238 Chassis(CrowApp &app) :
239 Node(app, "/redfish/v1/Chassis/<str>/", std::string())
240 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700241 entityPrivileges = {
242 {boost::beast::http::verb::get, {{"Login"}}},
243 {boost::beast::http::verb::head, {{"Login"}}},
244 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
245 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
246 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
247 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100248 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100249
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 private:
251 /**
252 * Functions triggers appropriate requests on DBus
253 */
254 void doGet(crow::Response &res, const crow::Request &req,
255 const std::vector<std::string> &params) override
256 {
Gunnar Mills734bfe92019-01-21 16:33:50 -0600257 const std::array<const char *, 3> interfaces = {
258 "xyz.openbmc_project.Inventory.Item.Board",
259 "xyz.openbmc_project.Inventory.Item.Chassis",
260 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
261
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 // Check if there is required param, truly entering this shall be
263 // impossible.
264 if (params.size() != 1)
265 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700266 messages::internalError(res);
Ed Tanousdaf36e22018-04-20 16:01:36 -0700267 res.end();
268 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269 }
Shawn McCarney99cffd72019-03-01 10:46:20 -0600270 const std::string &chassisId = params[0];
Gunnar Mills603a6642019-01-21 17:03:51 -0600271#ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
272 // In a one chassis system the only supported name is "chassis"
273 if (chassisId != "chassis")
274 {
275 messages::resourceNotFound(res, "#Chassis.v1_4_0.Chassis",
276 chassisId);
277 res.end();
278 return;
279 }
280#endif
Ed Tanouse0d918b2018-03-27 17:41:04 -0700281
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700282 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700284 [asyncResp, chassisId(std::string(chassisId))](
285 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 const std::vector<std::pair<
287 std::string, std::vector<std::pair<
288 std::string, std::vector<std::string>>>>>
289 &subtree) {
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700290 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700292 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 return;
294 }
295 // Iterate over all retrieved ObjectPaths.
296 for (const std::pair<
297 std::string,
298 std::vector<
299 std::pair<std::string, std::vector<std::string>>>>
300 &object : subtree)
301 {
302 const std::string &path = object.first;
303 const std::vector<
304 std::pair<std::string, std::vector<std::string>>>
305 &connectionNames = object.second;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700306
Gunnar Mills603a6642019-01-21 17:03:51 -0600307// If only one chassis, just select the first one
308#ifndef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309 if (!boost::ends_with(path, chassisId))
310 {
311 continue;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700312 }
Gunnar Mills603a6642019-01-21 17:03:51 -0600313#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314 if (connectionNames.size() < 1)
315 {
316 BMCWEB_LOG_ERROR << "Only got "
317 << connectionNames.size()
318 << " Connection names";
319 continue;
320 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700321
Johnathan Mantey49c53ac2019-05-02 09:22:38 -0700322 asyncResp->res.jsonValue["@odata.type"] =
323 "#Chassis.v1_4_0.Chassis";
324 asyncResp->res.jsonValue["@odata.id"] =
325 "/redfish/v1/Chassis/" + chassisId;
326 asyncResp->res.jsonValue["@odata.context"] =
327 "/redfish/v1/$metadata#Chassis.Chassis";
328 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
329 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
330
331 const std::string &connectionName =
332 connectionNames[0].first;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700334 [asyncResp, chassisId(std::string(chassisId))](
335 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700336 const std::vector<std::pair<
337 std::string, VariantType>> &propertiesList) {
338 for (const std::pair<std::string, VariantType>
339 &property : propertiesList)
340 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600341 // Store DBus properties that are also Redfish
342 // properties with same name and a string value
343 const std::string &propertyName =
344 property.first;
345 if ((propertyName == "PartNumber") ||
346 (propertyName == "SerialNumber") ||
347 (propertyName == "Manufacturer") ||
348 (propertyName == "Model"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700349 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600350 const std::string *value =
351 std::get_if<std::string>(
352 &property.second);
353 if (value != nullptr)
354 {
355 asyncResp->res.jsonValue[propertyName] =
356 *value;
357 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358 }
359 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700360 asyncResp->res.jsonValue["Name"] = chassisId;
361 asyncResp->res.jsonValue["Id"] = chassisId;
362 asyncResp->res.jsonValue["Thermal"] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700363 {"@odata.id", "/redfish/v1/Chassis/" +
364 chassisId + "/Thermal"}};
Ed Tanous2474adf2018-09-05 16:31:16 -0700365 // Power object
366 asyncResp->res.jsonValue["Power"] = {
367 {"@odata.id", "/redfish/v1/Chassis/" +
368 chassisId + "/Power"}};
Ed Tanous029573d2019-02-01 10:57:49 -0800369 asyncResp->res.jsonValue["Status"] = {
370 {"Health", "OK"},
371 {"State", "Enabled"},
372 };
Ed Tanous2474adf2018-09-05 16:31:16 -0700373
Ed Tanous029573d2019-02-01 10:57:49 -0800374 asyncResp->res
375 .jsonValue["Links"]["ComputerSystems"] = {
376 {{"@odata.id", "/redfish/v1/Systems/system"}}};
377 asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
378 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600379 getChassisState(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700380 },
381 connectionName, path, "org.freedesktop.DBus.Properties",
382 "GetAll",
383 "xyz.openbmc_project.Inventory.Decorator.Asset");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 return;
385 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700386
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387 // Couldn't find an object with that name. return an error
Jason M. Billsf12894f2018-10-09 12:45:45 -0700388 messages::resourceNotFound(
389 asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700390 },
391 "xyz.openbmc_project.ObjectMapper",
392 "/xyz/openbmc_project/object_mapper",
393 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600394 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Qiang XUc1819422019-02-27 13:51:32 +0800395
396 getPhysicalSecurityData(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700397 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700398};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399} // namespace redfish