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