blob: f78789a8a8d1f158d0db51f5a133b90ac1b35799 [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 Tanous0f74e642018-11-12 15:17:05 -0800282 res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis";
Shawn McCarney99cffd72019-03-01 10:46:20 -0600283 res.jsonValue["@odata.id"] = "/redfish/v1/Chassis/" + chassisId;
Ed Tanous0f74e642018-11-12 15:17:05 -0800284 res.jsonValue["@odata.context"] =
285 "/redfish/v1/$metadata#Chassis.Chassis";
286 res.jsonValue["Name"] = "Chassis Collection";
287 res.jsonValue["ChassisType"] = "RackMount";
Ed Tanous0f74e642018-11-12 15:17:05 -0800288
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700289 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700291 [asyncResp, chassisId(std::string(chassisId))](
292 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 const std::vector<std::pair<
294 std::string, std::vector<std::pair<
295 std::string, std::vector<std::string>>>>>
296 &subtree) {
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700297 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700299 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300 return;
301 }
302 // Iterate over all retrieved ObjectPaths.
303 for (const std::pair<
304 std::string,
305 std::vector<
306 std::pair<std::string, std::vector<std::string>>>>
307 &object : subtree)
308 {
309 const std::string &path = object.first;
310 const std::vector<
311 std::pair<std::string, std::vector<std::string>>>
312 &connectionNames = object.second;
Ed Tanouse0d918b2018-03-27 17:41:04 -0700313
Gunnar Mills603a6642019-01-21 17:03:51 -0600314// If only one chassis, just select the first one
315#ifndef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316 if (!boost::ends_with(path, chassisId))
317 {
318 continue;
Ed Tanousdaf36e22018-04-20 16:01:36 -0700319 }
Gunnar Mills603a6642019-01-21 17:03:51 -0600320#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 if (connectionNames.size() < 1)
322 {
323 BMCWEB_LOG_ERROR << "Only got "
324 << connectionNames.size()
325 << " Connection names";
326 continue;
327 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700328
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 const std::string connectionName = connectionNames[0].first;
330 crow::connections::systemBus->async_method_call(
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700331 [asyncResp, chassisId(std::string(chassisId))](
332 const boost::system::error_code ec,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 const std::vector<std::pair<
334 std::string, VariantType>> &propertiesList) {
335 for (const std::pair<std::string, VariantType>
336 &property : propertiesList)
337 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600338 // Store DBus properties that are also Redfish
339 // properties with same name and a string value
340 const std::string &propertyName =
341 property.first;
342 if ((propertyName == "PartNumber") ||
343 (propertyName == "SerialNumber") ||
344 (propertyName == "Manufacturer") ||
345 (propertyName == "Model"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700346 {
Shawn McCarney99cffd72019-03-01 10:46:20 -0600347 const std::string *value =
348 std::get_if<std::string>(
349 &property.second);
350 if (value != nullptr)
351 {
352 asyncResp->res.jsonValue[propertyName] =
353 *value;
354 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355 }
356 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700357 asyncResp->res.jsonValue["Name"] = chassisId;
358 asyncResp->res.jsonValue["Id"] = chassisId;
359 asyncResp->res.jsonValue["Thermal"] = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700360 {"@odata.id", "/redfish/v1/Chassis/" +
361 chassisId + "/Thermal"}};
Ed Tanous2474adf2018-09-05 16:31:16 -0700362 // Power object
363 asyncResp->res.jsonValue["Power"] = {
364 {"@odata.id", "/redfish/v1/Chassis/" +
365 chassisId + "/Power"}};
Ed Tanous029573d2019-02-01 10:57:49 -0800366 asyncResp->res.jsonValue["Status"] = {
367 {"Health", "OK"},
368 {"State", "Enabled"},
369 };
Ed Tanous2474adf2018-09-05 16:31:16 -0700370
Ed Tanous029573d2019-02-01 10:57:49 -0800371 asyncResp->res
372 .jsonValue["Links"]["ComputerSystems"] = {
373 {{"@odata.id", "/redfish/v1/Systems/system"}}};
374 asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
375 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600376 getChassisState(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377 },
378 connectionName, path, "org.freedesktop.DBus.Properties",
379 "GetAll",
380 "xyz.openbmc_project.Inventory.Decorator.Asset");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700381 return;
382 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700383
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 // Couldn't find an object with that name. return an error
Jason M. Billsf12894f2018-10-09 12:45:45 -0700385 messages::resourceNotFound(
386 asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387 },
388 "xyz.openbmc_project.ObjectMapper",
389 "/xyz/openbmc_project/object_mapper",
390 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Gunnar Mills734bfe92019-01-21 16:33:50 -0600391 "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
Qiang XUc1819422019-02-27 13:51:32 +0800392
393 getPhysicalSecurityData(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 }
Ed Tanous62d5e2e2018-09-05 16:17:25 -0700395};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700396} // namespace redfish