1 #include "fru-fault-monitor.hpp" 2 3 #include "elog-errors.hpp" 4 #include "xyz/openbmc_project/Led/Fru/Monitor/error.hpp" 5 #include "xyz/openbmc_project/Led/Mapper/error.hpp" 6 7 #include <phosphor-logging/elog.hpp> 8 #include <sdbusplus/exception.hpp> 9 10 namespace phosphor 11 { 12 namespace led 13 { 14 namespace fru 15 { 16 namespace fault 17 { 18 namespace monitor 19 { 20 21 using namespace phosphor::logging; 22 23 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 24 constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper"; 25 constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper"; 26 constexpr auto OBJMGR_IFACE = "org.freedesktop.DBus.ObjectManager"; 27 constexpr auto LED_GROUPS = "/xyz/openbmc_project/led/groups/"; 28 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging"; 29 constexpr auto LOG_IFACE = "xyz.openbmc_project.Logging.Entry"; 30 31 using AssociationList = 32 std::vector<std::tuple<std::string, std::string, std::string>>; 33 using Attributes = sdbusplus::message::variant<bool, AssociationList>; 34 using PropertyName = std::string; 35 using PropertyMap = std::map<PropertyName, Attributes>; 36 using InterfaceName = std::string; 37 using InterfaceMap = std::map<InterfaceName, PropertyMap>; 38 39 using Service = std::string; 40 using Path = std::string; 41 using Interface = std::string; 42 using Interfaces = std::vector<Interface>; 43 using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>; 44 45 using MethodErr = 46 sdbusplus::xyz::openbmc_project::Led::Mapper::Error::MethodError; 47 using ObjectNotFoundErr = 48 sdbusplus::xyz::openbmc_project::Led::Mapper::Error::ObjectNotFoundError; 49 using InventoryPathErr = sdbusplus::xyz::openbmc_project::Led::Fru::Monitor:: 50 Error::InventoryPathError; 51 52 std::string getService(sdbusplus::bus::bus& bus, const std::string& path) 53 { 54 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 55 MAPPER_IFACE, "GetObject"); 56 mapper.append(path.c_str(), std::vector<std::string>({OBJMGR_IFACE})); 57 auto mapperResponseMsg = bus.call(mapper); 58 if (mapperResponseMsg.is_method_error()) 59 { 60 using namespace xyz::openbmc_project::Led::Mapper; 61 elog<MethodErr>(MethodError::METHOD_NAME("GetObject"), 62 MethodError::PATH(path.c_str()), 63 MethodError::INTERFACE(OBJMGR_IFACE)); 64 } 65 66 std::map<std::string, std::vector<std::string>> mapperResponse; 67 try 68 { 69 mapperResponseMsg.read(mapperResponse); 70 } 71 catch (const sdbusplus::exception::SdBusError& e) 72 { 73 log<level::ERR>( 74 "Failed to parse getService mapper response", 75 entry("ERROR=%s", e.what()), 76 entry("REPLY_SIG=%s", mapperResponseMsg.get_signature())); 77 using namespace xyz::openbmc_project::Led::Mapper; 78 elog<ObjectNotFoundErr>(ObjectNotFoundError::METHOD_NAME("GetObject"), 79 ObjectNotFoundError::PATH(path.c_str()), 80 ObjectNotFoundError::INTERFACE(OBJMGR_IFACE)); 81 } 82 if (mapperResponse.empty()) 83 { 84 using namespace xyz::openbmc_project::Led::Mapper; 85 elog<ObjectNotFoundErr>(ObjectNotFoundError::METHOD_NAME("GetObject"), 86 ObjectNotFoundError::PATH(path.c_str()), 87 ObjectNotFoundError::INTERFACE(OBJMGR_IFACE)); 88 } 89 90 return mapperResponse.cbegin()->first; 91 } 92 93 void action(sdbusplus::bus::bus& bus, const std::string& path, bool assert) 94 { 95 std::string service; 96 try 97 { 98 std::string groups{LED_GROUPS}; 99 groups.pop_back(); 100 service = getService(bus, groups); 101 } 102 catch (MethodErr& e) 103 { 104 commit<MethodErr>(); 105 return; 106 } 107 catch (ObjectNotFoundErr& e) 108 { 109 commit<ObjectNotFoundErr>(); 110 return; 111 } 112 113 auto pos = path.rfind("/"); 114 if (pos == std::string::npos) 115 { 116 using namespace xyz::openbmc_project::Led::Fru::Monitor; 117 report<InventoryPathErr>(InventoryPathError::PATH(path.c_str())); 118 return; 119 } 120 auto unit = path.substr(pos + 1); 121 122 std::string ledPath = LED_GROUPS + unit + '_' + LED_FAULT; 123 124 auto method = bus.new_method_call(service.c_str(), ledPath.c_str(), 125 "org.freedesktop.DBus.Properties", "Set"); 126 method.append("xyz.openbmc_project.Led.Group"); 127 method.append("Asserted"); 128 129 method.append(sdbusplus::message::variant<bool>(assert)); 130 131 try 132 { 133 bus.call_noreply(method); 134 } 135 catch (const sdbusplus::exception::SdBusError& e) 136 { 137 // Log an info message, system may not have all the LED Groups defined 138 log<level::INFO>("Failed to Assert LED Group", 139 entry("ERROR=%s", e.what())); 140 } 141 142 return; 143 } 144 145 void Add::created(sdbusplus::message::message& msg) 146 { 147 auto bus = msg.get_bus(); 148 149 sdbusplus::message::object_path objectPath; 150 InterfaceMap interfaces; 151 try 152 { 153 msg.read(objectPath, interfaces); 154 } 155 catch (const sdbusplus::exception::SdBusError& e) 156 { 157 log<level::ERR>("Failed to parse created message", 158 entry("ERROR=%s", e.what()), 159 entry("REPLY_SIG=%s", msg.get_signature())); 160 return; 161 } 162 163 std::size_t found = objectPath.str.find(ELOG_ENTRY); 164 if (found == std::string::npos) 165 { 166 // Not a new error entry skip 167 return; 168 } 169 auto iter = interfaces.find("xyz.openbmc_project.Association.Definitions"); 170 if (iter == interfaces.end()) 171 { 172 return; 173 } 174 175 // Nothing else shows when a specific error log 176 // has been created. Do it here. 177 std::string message{objectPath.str + " created"}; 178 log<level::INFO>(message.c_str()); 179 180 auto attr = iter->second.find("Associations"); 181 if (attr == iter->second.end()) 182 { 183 return; 184 } 185 186 auto& assocs = 187 sdbusplus::message::variant_ns::get<AssociationList>(attr->second); 188 if (assocs.empty()) 189 { 190 // No associations skip 191 return; 192 } 193 194 for (const auto& item : assocs) 195 { 196 if (std::get<1>(item).compare(CALLOUT_REV_ASSOCIATION) == 0) 197 { 198 removeWatches.emplace_back( 199 std::make_unique<Remove>(bus, std::get<2>(item))); 200 action(bus, std::get<2>(item), true); 201 } 202 } 203 204 return; 205 } 206 207 void getLoggingSubTree(sdbusplus::bus::bus& bus, MapperResponseType& subtree) 208 { 209 auto depth = 0; 210 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 211 MAPPER_IFACE, "GetSubTree"); 212 mapperCall.append("/"); 213 mapperCall.append(depth); 214 mapperCall.append(std::vector<Interface>({LOG_IFACE})); 215 216 try 217 { 218 auto mapperResponseMsg = bus.call(mapperCall); 219 if (mapperResponseMsg.is_method_error()) 220 { 221 using namespace xyz::openbmc_project::Led::Mapper; 222 report<MethodErr>(MethodError::METHOD_NAME("GetSubTree"), 223 MethodError::PATH(MAPPER_OBJ_PATH), 224 MethodError::INTERFACE(OBJMGR_IFACE)); 225 return; 226 } 227 228 try 229 { 230 mapperResponseMsg.read(subtree); 231 } 232 catch (const sdbusplus::exception::SdBusError& e) 233 { 234 log<level::ERR>( 235 "Failed to parse existing callouts subtree message", 236 entry("ERROR=%s", e.what()), 237 entry("REPLY_SIG=%s", mapperResponseMsg.get_signature())); 238 } 239 } 240 catch (const sdbusplus::exception::SdBusError& e) 241 { 242 // Just means no log entries at the moment 243 } 244 } 245 246 void Add::processExistingCallouts(sdbusplus::bus::bus& bus) 247 { 248 MapperResponseType mapperResponse; 249 250 getLoggingSubTree(bus, mapperResponse); 251 if (mapperResponse.empty()) 252 { 253 // No errors to process. 254 return; 255 } 256 257 for (const auto& elem : mapperResponse) 258 { 259 auto method = bus.new_method_call( 260 elem.second.begin()->first.c_str(), elem.first.c_str(), 261 "org.freedesktop.DBus.Properties", "Get"); 262 method.append("xyz.openbmc_project.Association.Definitions"); 263 method.append("Associations"); 264 auto reply = bus.call(method); 265 if (reply.is_method_error()) 266 { 267 // do not stop, continue with next elog 268 log<level::ERR>("Error in getting associations"); 269 continue; 270 } 271 272 sdbusplus::message::variant<AssociationList> assoc; 273 try 274 { 275 reply.read(assoc); 276 } 277 catch (const sdbusplus::exception::SdBusError& e) 278 { 279 log<level::ERR>( 280 "Failed to parse existing callouts associations message", 281 entry("ERROR=%s", e.what()), 282 entry("REPLY_SIG=%s", reply.get_signature())); 283 continue; 284 } 285 auto& assocs = 286 sdbusplus::message::variant_ns::get<AssociationList>(assoc); 287 if (assocs.empty()) 288 { 289 // no associations, skip 290 continue; 291 } 292 293 for (const auto& item : assocs) 294 { 295 if (std::get<1>(item).compare(CALLOUT_REV_ASSOCIATION) == 0) 296 { 297 removeWatches.emplace_back( 298 std::make_unique<Remove>(bus, std::get<2>(item))); 299 action(bus, std::get<2>(item), true); 300 } 301 } 302 } 303 } 304 305 void Remove::removed(sdbusplus::message::message& msg) 306 { 307 auto bus = msg.get_bus(); 308 309 action(bus, inventoryPath, false); 310 return; 311 } 312 313 } // namespace monitor 314 } // namespace fault 315 } // namespace fru 316 } // namespace led 317 } // namespace phosphor 318