1 #pragma once
2
3 #include "async_resp.hpp"
4 #include "dbus_singleton.hpp"
5 #include "dbus_utility.hpp"
6 #include "error_messages.hpp"
7 #include "event_service_manager.hpp"
8 #include "http_request.hpp"
9 #include "http_response.hpp"
10 #include "logging.hpp"
11 #include "utils/dbus_utils.hpp"
12
13 #include <boost/system/error_code.hpp>
14 #include <boost/url/format.hpp>
15 #include <sdbusplus/unpack_properties.hpp>
16
17 #include <memory>
18 #include <string>
19 #include <string_view>
20
21 namespace redfish
22 {
23
afterGetSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & propertiesList)24 inline void afterGetSnmpTrapClientdata(
25 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26 const boost::system::error_code& ec,
27 const dbus::utility::DBusPropertiesMap& propertiesList)
28 {
29 if (ec)
30 {
31 BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
32 messages::internalError(asyncResp->res);
33 return;
34 }
35
36 std::string address;
37 uint16_t port = 0;
38
39 bool success = sdbusplus::unpackPropertiesNoThrow(
40 dbus_utils::UnpackErrorPrinter(), propertiesList, "Address", address,
41 "Port", port);
42
43 if (!success)
44 {
45 messages::internalError(asyncResp->res);
46 return;
47 }
48
49 asyncResp->res.jsonValue["Destination"] =
50 boost::urls::format("snmp://{}:{}", address, port);
51 }
52
53 inline void
getSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id,const std::string & objectPath)54 getSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55 const std::string& id, const std::string& objectPath)
56 {
57 asyncResp->res.jsonValue["@odata.type"] =
58 "#EventDestination.v1_8_0.EventDestination";
59 asyncResp->res.jsonValue["Protocol"] = "SNMPv2c";
60 asyncResp->res.jsonValue["@odata.id"] =
61 boost::urls::format("/redfish/v1/EventService/Subscriptions/{}", id);
62
63 asyncResp->res.jsonValue["Id"] = id;
64 asyncResp->res.jsonValue["Name"] = "Event Destination";
65
66 asyncResp->res.jsonValue["SubscriptionType"] = "SNMPTrap";
67 asyncResp->res.jsonValue["EventFormatType"] = "Event";
68
69 std::shared_ptr<Subscription> subValue =
70 EventServiceManager::getInstance().getSubscription(id);
71 if (subValue != nullptr)
72 {
73 asyncResp->res.jsonValue["Context"] = subValue->customText;
74 }
75 else
76 {
77 asyncResp->res.jsonValue["Context"] = "";
78 }
79
80 sdbusplus::asio::getAllProperties(
81 *crow::connections::systemBus, "xyz.openbmc_project.Network.SNMP",
82 objectPath, "xyz.openbmc_project.Network.Client",
83 [asyncResp](const boost::system::error_code& ec,
84 const dbus::utility::DBusPropertiesMap& properties) {
85 afterGetSnmpTrapClientdata(asyncResp, ec, properties);
86 });
87 }
88
89 inline void
getSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id)90 getSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
91 const std::string& id)
92 {
93 crow::connections::systemBus->async_method_call(
94 [asyncResp, id](const boost::system::error_code& ec,
95 dbus::utility::ManagedObjectType& resp) {
96 if (ec)
97 {
98 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}",
99 ec);
100 messages::internalError(asyncResp->res);
101 return;
102 }
103
104 for (const auto& objpath : resp)
105 {
106 sdbusplus::message::object_path path(objpath.first);
107 const std::string snmpId = path.filename();
108 if (snmpId.empty())
109 {
110 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
111 messages::internalError(asyncResp->res);
112 return;
113 }
114 const std::string subscriptionId = "snmp" + snmpId;
115 if (id != subscriptionId)
116 {
117 continue;
118 }
119
120 getSnmpTrapClientdata(asyncResp, id, objpath.first);
121 return;
122 }
123
124 messages::resourceNotFound(asyncResp->res, "Subscriptions", id);
125 EventServiceManager::getInstance().deleteSubscription(id);
126 },
127 "xyz.openbmc_project.Network.SNMP",
128 "/xyz/openbmc_project/network/snmp/manager",
129 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
130 }
131
afterSnmpClientCreate(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const sdbusplus::message_t & msg,const std::string & host,const std::string & dbusSNMPid)132 inline void afterSnmpClientCreate(
133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
134 const boost::system::error_code& ec, const sdbusplus::message_t& msg,
135 const std::string& host, const std::string& dbusSNMPid)
136 {
137 if (ec)
138 {
139 const sd_bus_error* dbusError = msg.get_error();
140 if (dbusError != nullptr)
141 {
142 if (std::string_view(
143 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
144 dbusError->name)
145 {
146 messages::propertyValueIncorrect(asyncResp->res, "Destination",
147 host);
148 return;
149 }
150 if (ec.value() != EBADR)
151 {
152 // SNMP not installed
153 messages::propertyValueOutOfRange(asyncResp->res, "SNMPv2c",
154 "Protocol");
155 return;
156 }
157 }
158 messages::internalError(asyncResp->res);
159 return;
160 }
161 sdbusplus::message::object_path path(dbusSNMPid);
162 const std::string snmpId = path.filename();
163 if (snmpId.empty())
164 {
165 messages::internalError(asyncResp->res);
166 return;
167 }
168
169 std::string subscriptionId = "snmp" + snmpId;
170
171 boost::urls::url uri = boost::urls::format(
172 "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
173 asyncResp->res.addHeader("Location", uri.buffer());
174 messages::created(asyncResp->res);
175 }
176
177 inline void
addSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & host,uint16_t snmpTrapPort)178 addSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
179 const std::string& host, uint16_t snmpTrapPort)
180 {
181 crow::connections::systemBus->async_method_call(
182 [asyncResp, host](const boost::system::error_code& ec,
183 const sdbusplus::message_t& msg,
184 const std::string& dbusSNMPid) {
185 afterSnmpClientCreate(asyncResp, ec, msg, host, dbusSNMPid);
186 },
187 "xyz.openbmc_project.Network.SNMP",
188 "/xyz/openbmc_project/network/snmp/manager",
189 "xyz.openbmc_project.Network.Client.Create", "Client", host,
190 snmpTrapPort);
191 }
192
193 inline void
getSnmpSubscriptionList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & snmpId,nlohmann::json & memberArray)194 getSnmpSubscriptionList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
195 const std::string& snmpId,
196 nlohmann::json& memberArray)
197 {
198 const std::string subscriptionId = "snmp" + snmpId;
199
200 nlohmann::json::object_t member;
201 member["@odata.id"] = boost::urls::format(
202 "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
203 memberArray.push_back(std::move(member));
204
205 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
206 }
207
208 inline void
deleteSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & param)209 deleteSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
210 const std::string& param)
211 {
212 std::string_view snmpTrapId = param;
213
214 // Erase "snmp" in the request to find the corresponding
215 // dbus snmp client id. For example, the snmpid in the
216 // request is "snmp1", which will be "1" after being erased.
217 snmpTrapId.remove_prefix(4);
218
219 sdbusplus::message::object_path snmpPath =
220 sdbusplus::message::object_path(
221 "/xyz/openbmc_project/network/snmp/manager") /
222 std::string(snmpTrapId);
223
224 crow::connections::systemBus->async_method_call(
225 [asyncResp, param](const boost::system::error_code& ec) {
226 if (ec)
227 {
228 // The snmp trap id is incorrect
229 if (ec.value() == EBADR)
230 {
231 messages::resourceNotFound(asyncResp->res, "Subscription",
232 param);
233 return;
234 }
235 messages::internalError(asyncResp->res);
236 return;
237 }
238 messages::success(asyncResp->res);
239 },
240 "xyz.openbmc_project.Network.SNMP", static_cast<std::string>(snmpPath),
241 "xyz.openbmc_project.Object.Delete", "Delete");
242 }
243
244 } // namespace redfish
245