Retrieve port info for systems service
In systems.hpp for Serialconsole, SSH service-enabled and its Port
number info is hardcoded. Same for IPMI service-enabled info is also
hardcoded.
Implementation:
SSH:
check for obmc-console-ssh@2200.service service is enable or not, and
yes then, on which port number. Retrieve service-related information
and pass that into DMTF for "/redfish/v1/Systems/system/".
IPMI:-
check for phosphor-ipmi-net@eth0.socket service is enable or not, and
pass that info DMTF for "/redfish/v1/Systems/system/".
Tested:
Manually tested on the Witherspoon system, there is no change in output.
Run Redfish validator. No error found.
Before:
"SerialConsole": {
"IPMI": {
"ServiceEnabled": true
},
"MaxConcurrentSessions": 15,
"SSH": {
"HotKeySequenceDisplay": "Press ~. to exit console",
"Port": 2200,
"ServiceEnabled": true
}
}
After:
Note: SSH Info retrieve via Dbus ListUnit API
"SerialConsole": {
"IPMI": {
"ServiceEnabled": true
},
"MaxConcurrentSessions": 15,
"SSH": {
"HotKeySequenceDisplay": "Press ~. to exit console",
"Port": 2200,
"ServiceEnabled": true
}
}
Signed-off-by: Abhishek Patel <Abhishek.Patel@ibm.com>
Change-Id: I70009ee785aab3ca4a61fe0d96fbc5b340831647
diff --git a/redfish-core/lib/network_protocol.hpp b/redfish-core/lib/network_protocol.hpp
index 8e2fc4b..00b7bfc 100644
--- a/redfish-core/lib/network_protocol.hpp
+++ b/redfish-core/lib/network_protocol.hpp
@@ -39,13 +39,16 @@
void getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp);
std::string getHostName();
-static constexpr const char* sshServiceName = "dropbear";
-static constexpr const char* httpsServiceName = "bmcweb";
-static constexpr const char* ipmiServiceName = "phosphor-ipmi-net";
-static constexpr std::array<std::pair<const char*, const char*>, 3>
- protocolToService = {{{"SSH", sshServiceName},
- {"HTTPS", httpsServiceName},
- {"IPMI", ipmiServiceName}}};
+static constexpr std::string_view sshServiceName = "dropbear";
+static constexpr std::string_view httpsServiceName = "bmcweb";
+static constexpr std::string_view ipmiServiceName = "phosphor-ipmi-net";
+
+// Mapping from Redfish NetworkProtocol key name to backend service that hosts
+// that protocol.
+static constexpr std::array<std::pair<std::string_view, std::string_view>, 3>
+ networkProtocolToDbus = {{{"SSH", sshServiceName},
+ {"HTTPS", httpsServiceName},
+ {"IPMI", ipmiServiceName}}};
inline void extractNTPServersAndDomainNamesData(
const dbus::utility::ManagedObjectType& dbusData,
@@ -113,6 +116,38 @@
"org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
}
+inline void afterNetworkPortRequest(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code& ec,
+ const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
+{
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ for (const auto& data : socketData)
+ {
+ const std::string& socketPath = get<0>(data);
+ const std::string& protocolName = get<1>(data);
+ bool isProtocolEnabled = get<2>(data);
+
+ asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
+ isProtocolEnabled;
+ asyncResp->res.jsonValue[protocolName]["Port"] = nullptr;
+ getPortNumber(socketPath, [asyncResp, protocolName](
+ const boost::system::error_code& ec2,
+ int portNumber) {
+ if (ec2)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ asyncResp->res.jsonValue[protocolName]["Port"] = portNumber;
+ });
+ }
+}
+
inline void getNetworkData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const crow::Request& req)
{
@@ -134,7 +169,7 @@
// but from security perspective it is not recommended to use.
// Hence using protocolEnabled as false to make it OCP and security-wise
// compliant
- asyncResp->res.jsonValue["HTTP"]["Port"] = 0;
+ asyncResp->res.jsonValue["HTTP"]["Port"] = nullptr;
asyncResp->res.jsonValue["HTTP"]["ProtocolEnabled"] = false;
std::string hostName = getHostName();
@@ -179,43 +214,8 @@
"/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
}
- for (const auto& protocol : protocolToService)
- {
- const std::string& protocolName = protocol.first;
- const std::string& serviceName = protocol.second;
- getPortStatusAndPath(
- serviceName,
- [asyncResp, protocolName](const boost::system::error_code& ec,
- const std::string& socketPath,
- bool isProtocolEnabled) {
- // If the service is not installed, that is not an error
- if (ec == boost::system::errc::no_such_process)
- {
- asyncResp->res.jsonValue[protocolName]["Port"] =
- nlohmann::detail::value_t::null;
- asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
- false;
- return;
- }
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
- isProtocolEnabled;
- getPortNumber(socketPath, [asyncResp, protocolName](
- const boost::system::error_code& ec2,
- int portNumber) {
- if (ec2)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue[protocolName]["Port"] = portNumber;
- });
- });
- }
+ getPortStatusAndPath(std::span(networkProtocolToDbus),
+ std::bind_front(afterNetworkPortRequest, asyncResp));
} // namespace redfish
inline void handleNTPProtocolEnabled(
@@ -457,7 +457,7 @@
});
}
-inline std::string encodeServiceObjectPath(const std::string& serviceName)
+inline std::string encodeServiceObjectPath(std::string_view serviceName)
{
sdbusplus::message::object_path objPath(
"/xyz/openbmc_project/control/service");
diff --git a/redfish-core/lib/redfish_util.hpp b/redfish-core/lib/redfish_util.hpp
index 9d358c0..a742ca6 100644
--- a/redfish-core/lib/redfish_util.hpp
+++ b/redfish-core/lib/redfish_util.hpp
@@ -97,21 +97,25 @@
}
template <typename CallbackFunc>
-void getPortStatusAndPath(const std::string& serviceName,
- CallbackFunc&& callback)
+void getPortStatusAndPath(
+ std::span<const std::pair<std::string_view, std::string_view>>
+ protocolToDBus,
+ CallbackFunc&& callback)
{
crow::connections::systemBus->async_method_call(
- [serviceName, callback{std::forward<CallbackFunc>(callback)}](
+ [protocolToDBus, callback{std::forward<CallbackFunc>(callback)}](
const boost::system::error_code& ec,
const std::vector<UnitStruct>& r) {
+ std::vector<std::tuple<std::string, std::string, bool>> socketData;
if (ec)
{
BMCWEB_LOG_ERROR << ec;
// return error code
- callback(ec, "", false);
+ callback(ec, socketData);
return;
}
+ // save all service output into vector
for (const UnitStruct& unit : r)
{
// Only traverse through <xyz>.socket units
@@ -142,31 +146,31 @@
// unitsName without ".socket", only <xyz>
std::string unitNameStr = unitName.substr(0, lastCharPos);
- // We are interested in services, which starts with
- // mapped service name
- if (unitNameStr != serviceName)
+ for (const auto& kv : protocolToDBus)
{
- continue;
+ // We are interested in services, which starts with
+ // mapped service name
+ if (unitNameStr != kv.second)
+ {
+ continue;
+ }
+
+ const std::string& socketPath =
+ std::get<NET_PROTO_UNIT_OBJ_PATH>(unit);
+ const std::string& unitState =
+ std::get<NET_PROTO_UNIT_SUB_STATE>(unit);
+
+ bool isProtocolEnabled =
+ ((unitState == "running") || (unitState == "listening"));
+
+ socketData.emplace_back(socketPath, std::string(kv.first),
+ isProtocolEnabled);
+ // We found service, return from inner loop.
+ break;
}
-
- const std::string& socketPath =
- std::get<NET_PROTO_UNIT_OBJ_PATH>(unit);
- const std::string& unitState =
- std::get<NET_PROTO_UNIT_SUB_STATE>(unit);
-
- bool isProtocolEnabled =
- ((unitState == "running") || (unitState == "listening"));
- // We found service, return from inner loop.
- callback(ec, socketPath, isProtocolEnabled);
- return;
}
- // no service foudn, throw error
- boost::system::error_code ec1 = boost::system::errc::make_error_code(
- boost::system::errc::no_such_process);
- // return error code
- callback(ec1, "", false);
- BMCWEB_LOG_ERROR << ec1;
+ callback(ec, socketData);
},
"org.freedesktop.systemd1", "/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager", "ListUnits");
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 59abd4f..6174610 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -41,6 +41,10 @@
namespace redfish
{
+const static std::array<std::pair<std::string_view, std::string_view>, 2>
+ protocolToDBusForSystems{
+ {{"SSH", "obmc-console-ssh"}, {"IPMI", "phosphor-ipmi-net"}}};
+
/**
* @brief Updates the Functional State of DIMMs
*
@@ -2879,6 +2883,42 @@
"</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
}
+inline void afterPortRequest(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code& ec,
+ const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
+{
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ for (const auto& data : socketData)
+ {
+ const std::string& socketPath = get<0>(data);
+ const std::string& protocolName = get<1>(data);
+ bool isProtocolEnabled = get<2>(data);
+ nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"];
+ dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled;
+ // need to retrieve port number for
+ // obmc-console-ssh service
+ if (protocolName == "SSH")
+ {
+ getPortNumber(socketPath, [asyncResp, protocolName](
+ const boost::system::error_code ec1,
+ int portNumber) {
+ if (ec1)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ nlohmann::json& dataJson1 =
+ asyncResp->res.jsonValue["SerialConsole"];
+ dataJson1[protocolName]["Port"] = portNumber;
+ });
+ }
+ }
+}
/**
* Systems derived class for delivering Computer Systems Schema.
*/
@@ -2965,6 +3005,8 @@
asyncResp->res
.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
"Press ~. to exit console";
+ getPortStatusAndPath(std::span{protocolToDBusForSystems},
+ std::bind_front(afterPortRequest, asyncResp));
#ifdef BMCWEB_ENABLE_KVM
// Fill in GraphicalConsole info