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