Skip to content

Commit b4bec66

Browse files
Abhishek Pateledtanous
Abhishek Patel
authored andcommitted
Move getPortInfo to Redfish Utility
Plan to use getPortInfo() to get the SSH SerialConsole in the ComputerSystem. This commit moves the getPortInfo functionality into the redfish utility. Tested: manually tested on Witherspoon system, there is no change in output. Run Redfish validator, no error found. Before: "HTTPS": { "Certificates": { "@odata.id": "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/ Certificates" }, "Port": 443, "ProtocolEnabled": true }, "IPMI": { "Port": 623, "ProtocolEnabled": true }, "SSH": { "Port": 22, "ProtocolEnabled": true } After: "HTTPS": { "Certificates": { "@odata.id": "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/ Certificates" }, "Port": 443, "ProtocolEnabled": true }, "IPMI": { "Port": 623, "ProtocolEnabled": true }, "SSH": { "Port": 22, "ProtocolEnabled": true } Change-Id: I126827fbbecec59adcf630b88e31bc5ff8151588 Signed-off-by: Abhishek Patel <[email protected]>
1 parent 11a2f0f commit b4bec66

File tree

2 files changed

+205
-134
lines changed

2 files changed

+205
-134
lines changed

redfish-core/lib/network_protocol.hpp

+41-134
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "error_messages.hpp"
1919
#include "openbmc_dbus_rest.hpp"
20+
#include "redfish_util.hpp"
2021

2122
#include <app.hpp>
2223
#include <registries/privilege_registry.hpp>
@@ -30,35 +31,7 @@ namespace redfish
3031
void getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp);
3132
std::string getHostName();
3233

33-
enum NetworkProtocolUnitStructFields
34-
{
35-
NET_PROTO_UNIT_NAME,
36-
NET_PROTO_UNIT_DESC,
37-
NET_PROTO_UNIT_LOAD_STATE,
38-
NET_PROTO_UNIT_ACTIVE_STATE,
39-
NET_PROTO_UNIT_SUB_STATE,
40-
NET_PROTO_UNIT_DEVICE,
41-
NET_PROTO_UNIT_OBJ_PATH,
42-
NET_PROTO_UNIT_ALWAYS_0,
43-
NET_PROTO_UNIT_ALWAYS_EMPTY,
44-
NET_PROTO_UNIT_ALWAYS_ROOT_PATH
45-
};
46-
47-
enum NetworkProtocolListenResponseElements
48-
{
49-
NET_PROTO_LISTEN_TYPE,
50-
NET_PROTO_LISTEN_STREAM
51-
};
52-
53-
/**
54-
* @brief D-Bus Unit structure returned in array from ListUnits Method
55-
*/
56-
using UnitStruct =
57-
std::tuple<std::string, std::string, std::string, std::string, std::string,
58-
std::string, sdbusplus::message::object_path, uint32_t,
59-
std::string, sdbusplus::message::object_path>;
60-
61-
const static std::array<std::pair<const char*, const char*>, 3> protocolToDBus{
34+
const static std::array<std::pair<std::string, std::string>, 3> protocolToDBus{
6235
{{"SSH", "dropbear"}, {"HTTPS", "bmcweb"}, {"IPMI", "phosphor-ipmi-net"}}};
6336

6437
inline void
@@ -191,114 +164,48 @@ inline void getNetworkData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191164
Privileges effectiveUserPrivileges =
192165
redfish::getUserPrivileges(req.userRole);
193166

194-
crow::connections::systemBus->async_method_call(
195-
[asyncResp,
196-
&effectiveUserPrivileges](const boost::system::error_code e,
197-
const std::vector<UnitStruct>& r) {
198-
if (e)
199-
{
200-
asyncResp->res.jsonValue = nlohmann::json::object();
201-
messages::internalError(asyncResp->res);
202-
return;
203-
}
204-
// /redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates is
205-
// something only ConfigureManager can access then only display when
206-
// the user has permissions ConfigureManager
207-
if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
208-
effectiveUserPrivileges))
209-
{
210-
asyncResp->res.jsonValue["HTTPS"]["Certificates"] = {
211-
{"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol/"
212-
"HTTPS/Certificates"}};
213-
}
214-
for (auto& unit : r)
215-
{
216-
/* Only traverse through <xyz>.socket units */
217-
const std::string& unitName =
218-
std::get<NET_PROTO_UNIT_NAME>(unit);
219-
if (!boost::ends_with(unitName, ".socket"))
220-
{
221-
continue;
222-
}
167+
// /redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates is
168+
// something only ConfigureManager can access then only display when
169+
// the user has permissions ConfigureManager
170+
if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
171+
effectiveUserPrivileges))
172+
{
173+
asyncResp->res.jsonValue["HTTPS"]["Certificates"] = {
174+
{"@odata.id",
175+
"/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"}};
176+
}
223177

224-
for (auto& kv : protocolToDBus)
178+
for (const auto& protocol : protocolToDBus)
179+
{
180+
const std::string& protocolName = protocol.first;
181+
const std::string& serviceName = protocol.second;
182+
getPortStatusAndPath(
183+
serviceName,
184+
[asyncResp, protocolName](const boost::system::error_code ec,
185+
const std::string& socketPath,
186+
bool isProtocolEnabled) {
187+
if (ec)
225188
{
226-
// We are interested in services, which starts with
227-
// mapped service name
228-
if (!boost::starts_with(unitName, kv.second))
229-
{
230-
continue;
231-
}
232-
const char* rfServiceKey = kv.first;
233-
const std::string& socketPath =
234-
std::get<NET_PROTO_UNIT_OBJ_PATH>(unit);
235-
const std::string& unitState =
236-
std::get<NET_PROTO_UNIT_SUB_STATE>(unit);
237-
238-
asyncResp->res.jsonValue[rfServiceKey]["ProtocolEnabled"] =
239-
(unitState == "running") || (unitState == "listening");
240-
241-
crow::connections::systemBus->async_method_call(
242-
[asyncResp, rfServiceKey{std::string(rfServiceKey)}](
243-
const boost::system::error_code ec,
244-
const std::variant<std::vector<
245-
std::tuple<std::string, std::string>>>& resp) {
246-
if (ec)
247-
{
248-
messages::internalError(asyncResp->res);
249-
return;
250-
}
251-
const std::vector<
252-
std::tuple<std::string, std::string>>*
253-
responsePtr = std::get_if<std::vector<
254-
std::tuple<std::string, std::string>>>(
255-
&resp);
256-
if (responsePtr == nullptr ||
257-
responsePtr->size() < 1)
258-
{
259-
return;
260-
}
261-
262-
const std::string& listenStream =
263-
std::get<NET_PROTO_LISTEN_STREAM>(
264-
(*responsePtr)[0]);
265-
std::size_t lastColonPos = listenStream.rfind(':');
266-
if (lastColonPos == std::string::npos)
267-
{
268-
// Not a port
269-
return;
270-
}
271-
std::string portStr =
272-
listenStream.substr(lastColonPos + 1);
273-
if (portStr.empty())
274-
{
275-
return;
276-
}
277-
char* endPtr = nullptr;
278-
errno = 0;
279-
// Use strtol instead of stroi to avoid
280-
// exceptions
281-
long port =
282-
std::strtol(portStr.c_str(), &endPtr, 10);
283-
if ((errno == 0) && (*endPtr == '\0'))
284-
{
285-
asyncResp->res.jsonValue[rfServiceKey]["Port"] =
286-
port;
287-
}
288-
return;
289-
},
290-
"org.freedesktop.systemd1", socketPath,
291-
"org.freedesktop.DBus.Properties", "Get",
292-
"org.freedesktop.systemd1.Socket", "Listen");
293-
294-
// We found service, break the inner loop.
295-
break;
189+
messages::internalError(asyncResp->res);
190+
return;
296191
}
297-
}
298-
},
299-
"org.freedesktop.systemd1", "/org/freedesktop/systemd1",
300-
"org.freedesktop.systemd1.Manager", "ListUnits");
301-
}
192+
asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
193+
isProtocolEnabled;
194+
getPortNumber(
195+
socketPath,
196+
[asyncResp, protocolName](
197+
const boost::system::error_code ec, int portNumber) {
198+
if (ec)
199+
{
200+
messages::internalError(asyncResp->res);
201+
return;
202+
}
203+
asyncResp->res.jsonValue[protocolName]["Port"] =
204+
portNumber;
205+
});
206+
});
207+
}
208+
} // namespace redfish
302209

303210
#ifdef BMCWEB_ALLOW_DEPRECATED_HOSTNAME_PATCH
304211
inline void

redfish-core/lib/redfish_util.hpp

+164
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,34 @@
1919
namespace redfish
2020
{
2121

22+
enum NetworkProtocolUnitStructFields
23+
{
24+
NET_PROTO_UNIT_NAME,
25+
NET_PROTO_UNIT_DESC,
26+
NET_PROTO_UNIT_LOAD_STATE,
27+
NET_PROTO_UNIT_ACTIVE_STATE,
28+
NET_PROTO_UNIT_SUB_STATE,
29+
NET_PROTO_UNIT_DEVICE,
30+
NET_PROTO_UNIT_OBJ_PATH,
31+
NET_PROTO_UNIT_ALWAYS_0,
32+
NET_PROTO_UNIT_ALWAYS_EMPTY,
33+
NET_PROTO_UNIT_ALWAYS_ROOT_PATH
34+
};
35+
36+
enum NetworkProtocolListenResponseElements
37+
{
38+
NET_PROTO_LISTEN_TYPE,
39+
NET_PROTO_LISTEN_STREAM
40+
};
41+
42+
/**
43+
* @brief D-Bus Unit structure returned in array from ListUnits Method
44+
*/
45+
using UnitStruct =
46+
std::tuple<std::string, std::string, std::string, std::string, std::string,
47+
std::string, sdbusplus::message::object_path, uint32_t,
48+
std::string, sdbusplus::message::object_path>;
49+
2250
template <typename CallbackFunc>
2351
void getMainChassisId(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
2452
CallbackFunc&& callback)
@@ -59,5 +87,141 @@ void getMainChassisId(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
5987
"xyz.openbmc_project.Inventory.Item.Board",
6088
"xyz.openbmc_project.Inventory.Item.Chassis"});
6189
}
90+
91+
template <typename CallbackFunc>
92+
void getPortStatusAndPath(const std::string& serviceName,
93+
CallbackFunc&& callback)
94+
{
95+
crow::connections::systemBus->async_method_call(
96+
[serviceName,
97+
callback{std::move(callback)}](const boost::system::error_code ec,
98+
const std::vector<UnitStruct>& r) {
99+
if (ec)
100+
{
101+
BMCWEB_LOG_ERROR << ec;
102+
// return error code
103+
callback(ec, "", false);
104+
return;
105+
}
106+
107+
for (const UnitStruct& unit : r)
108+
{
109+
// Only traverse through <xyz>.socket units
110+
const std::string& unitName =
111+
std::get<NET_PROTO_UNIT_NAME>(unit);
112+
113+
// find "." into unitsName
114+
size_t lastCharPos = unitName.rfind('.');
115+
if (lastCharPos == std::string::npos)
116+
{
117+
continue;
118+
}
119+
120+
// is unitsName end with ".socket"
121+
std::string unitNameEnd = unitName.substr(lastCharPos);
122+
if (unitNameEnd.compare(".socket") != 0)
123+
{
124+
continue;
125+
}
126+
127+
// find "@" into unitsName
128+
if (size_t atCharPos = unitName.rfind('@');
129+
atCharPos != std::string::npos)
130+
{
131+
lastCharPos = atCharPos;
132+
}
133+
134+
// unitsName without "@eth(x).socket", only <xyz>
135+
// unitsName without ".socket", only <xyz>
136+
std::string unitNameStr = unitName.substr(0, lastCharPos);
137+
138+
// We are interested in services, which starts with
139+
// mapped service name
140+
if (unitNameStr != serviceName)
141+
{
142+
continue;
143+
}
144+
145+
const std::string& socketPath =
146+
std::get<NET_PROTO_UNIT_OBJ_PATH>(unit);
147+
const std::string& unitState =
148+
std::get<NET_PROTO_UNIT_SUB_STATE>(unit);
149+
150+
bool isProtocolEnabled =
151+
((unitState == "running") || (unitState == "listening"));
152+
// We found service, return from inner loop.
153+
callback(ec, socketPath, isProtocolEnabled);
154+
return;
155+
}
156+
157+
// no service foudn, throw error
158+
boost::system::error_code ec1 =
159+
boost::system::errc::make_error_code(
160+
boost::system::errc::no_such_process);
161+
// return error code
162+
callback(ec1, "", false);
163+
BMCWEB_LOG_ERROR << ec1;
164+
},
165+
"org.freedesktop.systemd1", "/org/freedesktop/systemd1",
166+
"org.freedesktop.systemd1.Manager", "ListUnits");
167+
}
168+
169+
template <typename CallbackFunc>
170+
void getPortNumber(const std::string& socketPath, CallbackFunc&& callback)
171+
{
172+
crow::connections::systemBus->async_method_call(
173+
[callback{std::move(callback)}](
174+
const boost::system::error_code ec,
175+
const std::variant<
176+
std::vector<std::tuple<std::string, std::string>>>& resp) {
177+
if (ec)
178+
{
179+
BMCWEB_LOG_ERROR << ec;
180+
callback(ec, 0);
181+
return;
182+
}
183+
const std::vector<
184+
std::tuple<std::string, std::string>>* responsePtr =
185+
std::get_if<std::vector<std::tuple<std::string, std::string>>>(
186+
&resp);
187+
if (responsePtr == nullptr || responsePtr->size() < 1)
188+
{
189+
// Network Protocol Listen Response Elements is empty
190+
boost::system::error_code ec1 =
191+
boost::system::errc::make_error_code(
192+
boost::system::errc::bad_message);
193+
// return error code
194+
callback(ec1, 0);
195+
BMCWEB_LOG_ERROR << ec1;
196+
return;
197+
}
198+
const std::string& listenStream =
199+
std::get<NET_PROTO_LISTEN_STREAM>((*responsePtr)[0]);
200+
const char* pa = &listenStream[listenStream.rfind(':') + 1];
201+
int port{0};
202+
if (auto [p, ec2] = std::from_chars(pa, nullptr, port);
203+
ec2 != std::errc())
204+
{
205+
// there is only two possibility invalid_argument and
206+
// result_out_of_range
207+
boost::system::error_code ec3 =
208+
boost::system::errc::make_error_code(
209+
boost::system::errc::invalid_argument);
210+
if (ec2 == std::errc::result_out_of_range)
211+
{
212+
ec3 = boost::system::errc::make_error_code(
213+
boost::system::errc::result_out_of_range);
214+
}
215+
// return error code
216+
callback(ec3, 0);
217+
BMCWEB_LOG_ERROR << ec3;
218+
}
219+
callback(ec, port);
220+
},
221+
"org.freedesktop.systemd1", socketPath,
222+
"org.freedesktop.DBus.Properties", "Get",
223+
"org.freedesktop.systemd1.Socket", "Listen");
224+
}
225+
62226
} // namespace redfish
63227
#endif

0 commit comments

Comments
 (0)