blob: c2ea91d72ce9cd1f736f846bf7ea485b915bf74d [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"
19#include <boost/container/flat_map.hpp>
20
21namespace redfish {
22
23/**
24 * DBus types primitives for several generic DBus interfaces
25 * TODO(Pawel) consider move this to separate file into boost::dbus
26 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070027// Note, this is not a very useful variant, but because it isn't used to get
28// values, it should be as simple as possible
29// TODO(ed) invent a nullvariant type
30using VariantType = sdbusplus::message::variant<std::string>;
31using ManagedObjectsType = std::vector<std::pair<
32 sdbusplus::message::object_path,
33 std::vector<std::pair<std::string,
34 std::vector<std::pair<std::string, VariantType>>>>>>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010035
Ed Tanousaa2e59c2018-04-12 12:17:20 -070036using PropertiesType = boost::container::flat_map<std::string, VariantType>;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010037
38/**
39 * OnDemandChassisProvider
Gunnar Mills274fad52018-06-13 15:45:36 -050040 * Chassis provider class that retrieves data directly from dbus, before setting
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010041 * it into JSON output. This does not cache any data.
42 *
43 * Class can be a good example on how to scale different data providing
44 * solutions to produce single schema output.
45 *
46 * TODO(Pawel)
47 * This perhaps shall be different file, which has to be chosen on compile time
48 * depending on OEM needs
49 */
50class OnDemandChassisProvider {
51 public:
52 /**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010053 * Function that retrieves all Chassis available through EntityManager.
54 * @param callback a function that shall be called to convert Dbus output into
55 * JSON.
56 */
57 template <typename CallbackFunc>
58 void get_chassis_list(CallbackFunc &&callback) {
Ed Tanousdaf36e22018-04-20 16:01:36 -070059 const std::array<const char *, 4> interfaces = {
60 "xyz.openbmc_project.Inventory.Item.Board",
61 "xyz.openbmc_project.Inventory.Item.Chassis",
62 "xyz.openbmc_project.Inventory.Item.PowerSupply",
63 "xyz.openbmc_project.Inventory.Item.System",
64 };
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010065 crow::connections::system_bus->async_method_call(
66 [callback{std::move(callback)}](
67 const boost::system::error_code error_code,
Ed Tanousdaf36e22018-04-20 16:01:36 -070068 const std::vector<std::string> &resp) {
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010069 // Callback requires vector<string> to retrieve all available chassis
70 // list.
71 std::vector<std::string> chassis_list;
72 if (error_code) {
73 // Something wrong on DBus, the error_code is not important at this
74 // moment, just return success=false, and empty output. Since size
75 // of vector may vary depending on information from Entity Manager,
76 // and empty output could not be treated same way as error.
77 callback(false, chassis_list);
78 return;
79 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010080 // Iterate over all retrieved ObjectPaths.
Ed Tanousdaf36e22018-04-20 16:01:36 -070081 for (const std::string &objpath : resp) {
82 std::size_t last_pos = objpath.rfind("/");
83 if (last_pos != std::string::npos) {
84 // and put it into output vector.
85 chassis_list.emplace_back(objpath.substr(last_pos + 1));
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010086 }
87 }
Gunnar Mills274fad52018-06-13 15:45:36 -050088 // Finally make a callback with useful data
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010089 callback(true, chassis_list);
90 },
Ed Tanousdaf36e22018-04-20 16:01:36 -070091 "xyz.openbmc_project.ObjectMapper",
92 "/xyz/openbmc_project/object_mapper",
93 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
94 "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010095 };
96};
97
98/**
99 * ChassisCollection derived class for delivering Chassis Collection Schema
100 */
101class ChassisCollection : public Node {
102 public:
103 template <typename CrowApp>
104 ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") {
105 Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
106 Node::json["@odata.id"] = "/redfish/v1/Chassis";
107 Node::json["@odata.context"] =
108 "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
109 Node::json["Name"] = "Chassis Collection";
110
111 entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
112 {crow::HTTPMethod::HEAD, {{"Login"}}},
113 {crow::HTTPMethod::PATCH, {{"ConfigureComponents"}}},
114 {crow::HTTPMethod::PUT, {{"ConfigureComponents"}}},
115 {crow::HTTPMethod::DELETE, {{"ConfigureComponents"}}},
116 {crow::HTTPMethod::POST, {{"ConfigureComponents"}}}};
117 }
118
119 private:
120 /**
121 * Functions triggers appropriate requests on DBus
122 */
123 void doGet(crow::response &res, const crow::request &req,
124 const std::vector<std::string> &params) override {
125 // Get chassis list, and call the below callback for JSON preparation
126 chassis_provider.get_chassis_list(
127 [&](const bool &success, const std::vector<std::string> &output) {
128 if (success) {
129 // ... prepare json array with appropriate @odata.id links
130 nlohmann::json chassis_array = nlohmann::json::array();
131 for (const std::string &chassis_item : output) {
132 chassis_array.push_back(
133 {{"@odata.id", "/redfish/v1/Chassis/" + chassis_item}});
134 }
135 // Then attach members, count size and return,
136 Node::json["Members"] = chassis_array;
137 Node::json["Members@odata.count"] = chassis_array.size();
138 res.json_value = Node::json;
139 } else {
140 // ... otherwise, return INTERNALL ERROR
141 res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
142 }
143 res.end();
144 });
145 }
146
147 // Chassis Provider object
148 // TODO(Pawel) consider move it to singleton
149 OnDemandChassisProvider chassis_provider;
150};
151
152/**
153 * Chassis override class for delivering Chassis Schema
154 */
155class Chassis : public Node {
156 public:
157 /*
158 * Default Constructor
159 */
160 template <typename CrowApp>
161 Chassis(CrowApp &app)
162 : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) {
163 Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
164 Node::json["@odata.id"] = "/redfish/v1/Chassis";
165 Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
166 Node::json["Name"] = "Chassis Collection";
Ed Tanous6c233012018-03-15 14:43:56 -0700167 Node::json["ChassisType"] = "RackMount";
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100168
169 entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
170 {crow::HTTPMethod::HEAD, {{"Login"}}},
171 {crow::HTTPMethod::PATCH, {{"ConfigureComponents"}}},
172 {crow::HTTPMethod::PUT, {{"ConfigureComponents"}}},
173 {crow::HTTPMethod::DELETE, {{"ConfigureComponents"}}},
174 {crow::HTTPMethod::POST, {{"ConfigureComponents"}}}};
175 }
176
177 private:
178 /**
179 * Functions triggers appropriate requests on DBus
180 */
181 void doGet(crow::response &res, const crow::request &req,
182 const std::vector<std::string> &params) override {
183 // Check if there is required param, truly entering this shall be
184 // impossible.
185 if (params.size() != 1) {
186 res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
187 res.end();
188 return;
189 }
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100190
Ed Tanousdaf36e22018-04-20 16:01:36 -0700191 res.json_value = Node::json;
192 const std::string &chassis_id = params[0];
193 crow::connections::system_bus->async_method_call(
194 [&res, chassis_id(std::string(chassis_id)) ](
195 const boost::system::error_code error_code,
196 const std::vector<std::pair<
197 std::string,
198 std::vector<std::pair<std::string, std::vector<std::string>>>>>
199 &subtree) {
200 if (error_code) {
201 res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
202 res.json_value = {};
203 res.end();
204 return;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100205 }
Ed Tanousdaf36e22018-04-20 16:01:36 -0700206 // Iterate over all retrieved ObjectPaths.
207 for (const std::pair<std::string,
208 std::vector<std::pair<std::string,
209 std::vector<std::string>>>>
210 &object : subtree) {
211 const std::string &path = object.first;
212 const std::vector<std::pair<std::string, std::vector<std::string>>>
213 &connectionNames = object.second;
214 if (!boost::ends_with(path, chassis_id)) {
215 continue;
216 }
217 if (connectionNames.size() < 1) {
218 res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
219 res.end();
220 return;
221 }
222 const std::string connectionName = connectionNames[0].first;
223 crow::connections::system_bus->async_method_call(
224 [&res, chassis_id(std::string(chassis_id)) ](
225 const boost::system::error_code error_code,
226 const std::vector<std::pair<std::string, VariantType>>
227 &propertiesList) {
228 for (const std::pair<std::string, VariantType> &property :
229 propertiesList) {
230 const std::string *value =
231 mapbox::get_ptr<const std::string>(property.second);
232 if (value != nullptr) {
233 res.json_value[property.first] = *value;
234 }
235 }
236 res.json_value["Name"] = chassis_id;
237 res.json_value["Thermal"] = {
238 {"@odata.id",
239 "/redfish/v1/Chassis/" + chassis_id + "/Thermal"}};
240 res.end();
241 },
242 connectionName, path, "org.freedesktop.DBus.Properties",
243 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
244 // Found the connection we were looking for, return
245 return;
246 }
247 // Couldn't find an object with that name. return an error
248 res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100249 res.end();
Ed Tanousdaf36e22018-04-20 16:01:36 -0700250 },
251 "xyz.openbmc_project.ObjectMapper",
252 "/xyz/openbmc_project/object_mapper",
253 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
254 "/xyz/openbmc_project/inventory", int32_t(0),
255 std::array<const char *, 1>{
256 "xyz.openbmc_project.Inventory.Decorator.Asset"});
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100257 }
258
259 // Chassis Provider object
260 // TODO(Pawel) consider move it to singleton
261 OnDemandChassisProvider chassis_provider;
262};
263
264} // namespace redfish