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