blob: d24e641595687202ca1c31b1ee652c4983c19d85 [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/**
27 * DBus types primitives for several generic DBus interfaces
28 * TODO(Pawel) consider move this to separate file into boost::dbus
29 */
Ed Tanous55c7b7a2018-05-22 15:27:24 -070030// Note, this is not a very useful Variant, but because it isn't used to get
Ed Tanousaa2e59c2018-04-12 12:17:20 -070031// values, it should be as simple as possible
32// TODO(ed) invent a nullvariant type
Ed Tanousabf2add2019-01-22 16:40:12 -080033using VariantType = std::variant<bool, std::string, uint64_t>;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070034using ManagedObjectsType = std::vector<std::pair<
35 sdbusplus::message::object_path,
36 std::vector<std::pair<std::string,
37 std::vector<std::pair<std::string, VariantType>>>>>>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010038
Ed Tanousaa2e59c2018-04-12 12:17:20 -070039using PropertiesType = boost::container::flat_map<std::string, VariantType>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010040
Qiang XUc1819422019-02-27 13:51:32 +080041void getIntrusionByService(std::shared_ptr<AsyncResp> aResp,
42 const std::string &service,
43 const std::string &objPath)
44{
45 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
46
47 crow::connections::systemBus->async_method_call(
48 [aResp{std::move(aResp)}](const boost::system::error_code ec,
49 const std::variant<std::string> &value) {
50 if (ec)
51 {
52 // do not add err msg in redfish response, becaues this is not
53 // mandatory property
54 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
55 return;
56 }
57
58 const std::string *status = std::get_if<std::string>(&value);
59
60 if (status == nullptr)
61 {
62 BMCWEB_LOG_ERROR << "intrusion status read error \n";
63 return;
64 }
65
66 aResp->res.jsonValue["PhysicalSecurity"] = {
67 {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}};
68 },
69 service, objPath, "org.freedesktop.DBus.Properties", "Get",
70 "xyz.openbmc_project.Chassis.Intrusion", "Status");
71}
72
73/**
74 * Retrieves physical security properties over dbus
75 */
76void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp)
77{
78 crow::connections::systemBus->async_method_call(
79 [aResp{std::move(aResp)}](
80 const boost::system::error_code ec,
81 const std::vector<std::pair<
82 std::string,
83 std::vector<std::pair<std::string, std::vector<std::string>>>>>
84 &subtree) {
85 if (ec)
86 {
87 // do not add err msg in redfish response, becaues this is not
88 // mandatory property
89 BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec
90 << "\n";
91 return;
92 }
93 // Iterate over all retrieved ObjectPaths.
94 for (const auto &object : subtree)
95 {
96 for (const auto &service : object.second)
97 {
98 getIntrusionByService(aResp, service.first, object.first);
99 return;
100 }
101 }
102 },
103 "xyz.openbmc_project.ObjectMapper",
104 "/xyz/openbmc_project/object_mapper",
105 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
106 "/xyz/openbmc_project/Intrusion", int32_t(1),
107 std::array<const char *, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
108}
109
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100110/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100111 * ChassisCollection derived class for delivering Chassis Collection Schema
112 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113class ChassisCollection : public Node
114{
115 public:
116 ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
117 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118 entityPrivileges = {
119 {boost::beast::http::verb::get, {{"Login"}}},
120 {boost::beast::http::verb::head, {{"Login"}}},
121 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
122 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
123 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
124 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
125 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100126
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 private:
128 /**
129 * Functions triggers appropriate requests on DBus
130 */
131 void doGet(crow::Response &res, const crow::Request &req,
132 const std::vector<std::string> &params) override
133 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800134 res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
135 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
136 res.jsonValue["@odata.context"] =
137 "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
138 res.jsonValue["Name"] = "Chassis Collection";
139
Gunnar Mills603a6642019-01-21 17:03:51 -0600140#ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
141 // Assume one Chassis named "chassis"
142 res.jsonValue["Members@odata.count"] = 1;
143 res.jsonValue["Members"] = {
144 {{"@odata.id", "/redfish/v1/Chassis/chassis"}}};
145 res.end();
146 return;
147#endif
148 const std::array<const char *, 3> interfaces = {
149 "xyz.openbmc_project.Inventory.Item.Board",
150 "xyz.openbmc_project.Inventory.Item.Chassis",
151 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
152
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700153 auto asyncResp = std::make_shared<AsyncResp>(res);
154 crow::connections::systemBus->async_method_call(
155 [asyncResp](const boost::system::error_code ec,
156 const std::vector<std::string> &chassisList) {
157 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700158 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700159 messages::internalError(asyncResp->res);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700160 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700162 nlohmann::json &chassisArray =
163 asyncResp->res.jsonValue["Members"];
164 chassisArray = nlohmann::json::array();
165 for (const std::string &objpath : chassisList)
166 {
167 std::size_t lastPos = objpath.rfind("/");
168 if (lastPos == std::string::npos)
169 {
170 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
171 continue;
172 }
173 chassisArray.push_back(
174 {{"@odata.id", "/redfish/v1/Chassis/" +
175 objpath.substr(lastPos + 1)}});
176 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100177
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700178 asyncResp->res.jsonValue["Members@odata.count"] =
179 chassisArray.size();
180 },
181 "xyz.openbmc_project.ObjectMapper",
182 "/xyz/openbmc_project/object_mapper",
183 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600184 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700185 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100186};
187
188/**
189 * Chassis override class for delivering Chassis Schema
190 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700191class Chassis : public Node
192{
193 public:
194 Chassis(CrowApp &app) :
195 Node(app, "/redfish/v1/Chassis/<str>/", std::string())
196 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 entityPrivileges = {
198 {boost::beast::http::verb::get, {{"Login"}}},
199 {boost::beast::http::verb::head, {{"Login"}}},
200 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
201 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
202 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
203 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100204 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100205
Ed Tanous1abe55e2018-09-05 08:30:59 -0700206 private:
207 /**
208 * Functions triggers appropriate requests on DBus
209 */
210 void doGet(crow::Response &res, const crow::Request &req,
211 const std::vector<std::string> &params) override
212 {
Gunnar Mills734bfe92019-01-21 16:33:50 -0600213 const std::array<const char *, 3> interfaces = {
214 "xyz.openbmc_project.Inventory.Item.Board",
215 "xyz.openbmc_project.Inventory.Item.Chassis",
216 "xyz.openbmc_project.Inventory.Item.PowerSupply"};
217
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218 // Check if there is required param, truly entering this shall be
219 // impossible.
220 if (params.size() != 1)
221 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700222 messages::internalError(res);
Ed Tanousdaf36e22018-04-20 16:01:36 -0700223 res.end();
224 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 }
Shawn McCarney99cffd72019-03-01 10:46:20 -0600226 const std::string &chassisId = params[0];
Gunnar Mills603a6642019-01-21 17:03:51 -0600227#ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
228 // In a one chassis system the only supported name is "chassis"
229 if (chassisId != "chassis")
230 {
231 messages::resourceNotFound(res, "#Chassis.v1_4_0.Chassis",
232 chassisId);
233 res.end();
234 return;
235 }
236#endif
Ed Tanouse0d918b2018-03-27 17:41:04 -0700237
Ed Tanous0f74e642018-11-12 15:17:05 -0800238 res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis";
Shawn McCarney99cffd72019-03-01 10:46:20 -0600239 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis/" + chassisId;
Ed Tanous0f74e642018-11-12 15:17:05 -0800240 res.jsonValue["@odata.context"] =
241 "/redfish/v1/$metadata#Chassis.Chassis";
242 res.jsonValue["Name"] = "Chassis Collection";
243 res.jsonValue["ChassisType"] = "RackMount";
244 res.jsonValue["PowerState"] = "On";
245
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700246 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700247 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700248 [asyncResp, chassisId(std::string(chassisId))](
249 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 const std::vector<std::pair<
251 std::string, std::vector<std::pair<
252 std::string, std::vector<std::string>>>>>
253 &subtree) {
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700254 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700256 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 return;
258 }
259 // Iterate over all retrieved ObjectPaths.
260 for (const std::pair<
261 std::string,
262 std::vector<
263 std::pair<std::string, std::vector<std::string>>>>
264 &object : subtree)
265 {
266 const std::string &path = object.first;
267 const std::vector<
268 std::pair<std::string, std::vector<std::string>>>
269 &connectionNames = object.second;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700270
Gunnar Mills603a6642019-01-21 17:03:51 -0600271// If only one chassis, just select the first one
272#ifndef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 if (!boost::ends_with(path, chassisId))
274 {
275 continue;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700276 }
Gunnar Mills603a6642019-01-21 17:03:51 -0600277#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278 if (connectionNames.size() < 1)
279 {
280 BMCWEB_LOG_ERROR << "Only got "
281 << connectionNames.size()
282 << " Connection names";
283 continue;
284 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700285
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 const std::string connectionName = connectionNames[0].first;
287 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700288 [asyncResp, chassisId(std::string(chassisId))](
289 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 const std::vector<std::pair<
291 std::string, VariantType>> &propertiesList) {
292 for (const std::pair<std::string, VariantType>
293 &property : propertiesList)
294 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600295 // Store DBus properties that are also Redfish
296 // properties with same name and a string value
297 const std::string &propertyName =
298 property.first;
299 if ((propertyName == "PartNumber") ||
300 (propertyName == "SerialNumber") ||
301 (propertyName == "Manufacturer") ||
302 (propertyName == "Model"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600304 const std::string *value =
305 std::get_if<std::string>(
306 &property.second);
307 if (value != nullptr)
308 {
309 asyncResp->res.jsonValue[propertyName] =
310 *value;
311 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 }
313 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700314 asyncResp->res.jsonValue["Name"] = chassisId;
315 asyncResp->res.jsonValue["Id"] = chassisId;
316 asyncResp->res.jsonValue["Thermal"] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700317 {"@odata.id", "/redfish/v1/Chassis/" +
318 chassisId + "/Thermal"}};
Ed Tanous2474adf2018-09-05 16:31:16 -0700319 // Power object
320 asyncResp->res.jsonValue["Power"] = {
321 {"@odata.id", "/redfish/v1/Chassis/" +
322 chassisId + "/Power"}};
Ed Tanous029573d2019-02-01 10:57:49 -0800323 asyncResp->res.jsonValue["Status"] = {
324 {"Health", "OK"},
325 {"State", "Enabled"},
326 };
Ed Tanous2474adf2018-09-05 16:31:16 -0700327
Ed Tanous029573d2019-02-01 10:57:49 -0800328 asyncResp->res
329 .jsonValue["Links"]["ComputerSystems"] = {
330 {{"@odata.id", "/redfish/v1/Systems/system"}}};
331 asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
332 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 },
334 connectionName, path, "org.freedesktop.DBus.Properties",
335 "GetAll",
336 "xyz.openbmc_project.Inventory.Decorator.Asset");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337 return;
338 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700339
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340 // Couldn't find an object with that name. return an error
Jason M. Billsf12894f2018-10-09 12:45:45 -0700341 messages::resourceNotFound(
342 asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700343 },
344 "xyz.openbmc_project.ObjectMapper",
345 "/xyz/openbmc_project/object_mapper",
346 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600347 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Qiang XUc1819422019-02-27 13:51:32 +0800348
349 getPhysicalSecurityData(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700351};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700352} // namespace redfish