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