1e0017ebbSMatt Spinler /** 2e0017ebbSMatt Spinler * Copyright © 2018 IBM Corporation 3e0017ebbSMatt Spinler * 4e0017ebbSMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License"); 5e0017ebbSMatt Spinler * you may not use this file except in compliance with the License. 6e0017ebbSMatt Spinler * You may obtain a copy of the License at 7e0017ebbSMatt Spinler * 8e0017ebbSMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0 9e0017ebbSMatt Spinler * 10e0017ebbSMatt Spinler * Unless required by applicable law or agreed to in writing, software 11e0017ebbSMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS, 12e0017ebbSMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e0017ebbSMatt Spinler * See the License for the specific language governing permissions and 14e0017ebbSMatt Spinler * limitations under the License. 15e0017ebbSMatt Spinler */ 16*52ee71bdSMatt Spinler #include "callout.hpp" 17e0017ebbSMatt Spinler #include "config.h" 18e0017ebbSMatt Spinler #include "manager.hpp" 194a6ea6afSMatt Spinler #include "policy_find.hpp" 20e0017ebbSMatt Spinler 21e0017ebbSMatt Spinler namespace ibm 22e0017ebbSMatt Spinler { 23e0017ebbSMatt Spinler namespace logging 24e0017ebbSMatt Spinler { 25e0017ebbSMatt Spinler 26*52ee71bdSMatt Spinler namespace fs = std::experimental::filesystem; 27*52ee71bdSMatt Spinler 28e0017ebbSMatt Spinler Manager::Manager(sdbusplus::bus::bus& bus) : 29e0017ebbSMatt Spinler bus(bus), 30259e7277SMatt Spinler addMatch(bus, 31e0017ebbSMatt Spinler sdbusplus::bus::match::rules::interfacesAdded() + 32e0017ebbSMatt Spinler sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH), 33259e7277SMatt Spinler std::bind(std::mem_fn(&Manager::interfaceAdded), this, 34055da3bdSMatt Spinler std::placeholders::_1)), 35055da3bdSMatt Spinler removeMatch(bus, 36055da3bdSMatt Spinler sdbusplus::bus::match::rules::interfacesRemoved() + 37055da3bdSMatt Spinler sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH), 38055da3bdSMatt Spinler std::bind(std::mem_fn(&Manager::interfaceRemoved), this, 39259e7277SMatt Spinler std::placeholders::_1)) 40743e5822SMatt Spinler #ifdef USE_POLICY_INTERFACE 41259e7277SMatt Spinler , 42259e7277SMatt Spinler policies(POLICY_JSON_PATH) 43743e5822SMatt Spinler #endif 44e0017ebbSMatt Spinler { 4554bfa7e7SMatt Spinler createAll(); 4654bfa7e7SMatt Spinler } 4754bfa7e7SMatt Spinler 4854bfa7e7SMatt Spinler void Manager::createAll() 4954bfa7e7SMatt Spinler { 50259e7277SMatt Spinler auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH); 5154bfa7e7SMatt Spinler 5254bfa7e7SMatt Spinler for (const auto& object : objects) 5354bfa7e7SMatt Spinler { 5454bfa7e7SMatt Spinler const auto& interfaces = object.second; 5554bfa7e7SMatt Spinler 56e6a51590SMatt Spinler auto propertyMap = interfaces.find(LOGGING_IFACE); 5754bfa7e7SMatt Spinler 5854bfa7e7SMatt Spinler if (propertyMap != interfaces.end()) 5954bfa7e7SMatt Spinler { 60e6a51590SMatt Spinler createWithRestore(object.first, interfaces); 6154bfa7e7SMatt Spinler } 6254bfa7e7SMatt Spinler } 6354bfa7e7SMatt Spinler } 6454bfa7e7SMatt Spinler 65e6a51590SMatt Spinler void Manager::createWithRestore(const std::string& objectPath, 66e6a51590SMatt Spinler const DbusInterfaceMap& interfaces) 67e6a51590SMatt Spinler { 68e6a51590SMatt Spinler createObject(objectPath, interfaces); 69e6a51590SMatt Spinler 70e6a51590SMatt Spinler // TODO 71e6a51590SMatt Spinler // restoreCalloutObjects(objectPath, interfaces); 72e6a51590SMatt Spinler } 73e6a51590SMatt Spinler 74259e7277SMatt Spinler void Manager::create(const std::string& objectPath, 75e6a51590SMatt Spinler const DbusInterfaceMap& interfaces) 7654bfa7e7SMatt Spinler { 77e6a51590SMatt Spinler createObject(objectPath, interfaces); 784a6ea6afSMatt Spinler 79*52ee71bdSMatt Spinler createCalloutObjects(objectPath, interfaces); 80e6a51590SMatt Spinler } 81e6a51590SMatt Spinler 82e6a51590SMatt Spinler void Manager::createObject(const std::string& objectPath, 83e6a51590SMatt Spinler const DbusInterfaceMap& interfaces) 84e6a51590SMatt Spinler { 854a6ea6afSMatt Spinler #ifdef USE_POLICY_INTERFACE 86e6a51590SMatt Spinler auto logInterface = interfaces.find(LOGGING_IFACE); 87e6a51590SMatt Spinler createPolicyInterface(objectPath, logInterface->second); 884a6ea6afSMatt Spinler #endif 89e0017ebbSMatt Spinler } 90e0017ebbSMatt Spinler 91a1390353SMatt Spinler void Manager::erase(EntryID id) 92a1390353SMatt Spinler { 93*52ee71bdSMatt Spinler fs::remove_all(getSaveDir(id)); 94677143bbSMatt Spinler childEntries.erase(id); 95a1390353SMatt Spinler entries.erase(id); 96a1390353SMatt Spinler } 97a1390353SMatt Spinler 98491fc6f1SMatt Spinler void Manager::addInterface(const std::string& objectPath, InterfaceType type, 99491fc6f1SMatt Spinler std::experimental::any& object) 100491fc6f1SMatt Spinler { 101491fc6f1SMatt Spinler auto id = getEntryID(objectPath); 102491fc6f1SMatt Spinler auto entry = entries.find(id); 103491fc6f1SMatt Spinler 104491fc6f1SMatt Spinler if (entry == entries.end()) 105491fc6f1SMatt Spinler { 106491fc6f1SMatt Spinler InterfaceMap interfaces; 107491fc6f1SMatt Spinler interfaces.emplace(type, object); 108491fc6f1SMatt Spinler entries.emplace(id, std::move(interfaces)); 109491fc6f1SMatt Spinler } 110491fc6f1SMatt Spinler else 111491fc6f1SMatt Spinler { 112491fc6f1SMatt Spinler entry->second.emplace(type, object); 113491fc6f1SMatt Spinler } 114491fc6f1SMatt Spinler } 115491fc6f1SMatt Spinler 116677143bbSMatt Spinler void Manager::addChildInterface(const std::string& objectPath, 117677143bbSMatt Spinler InterfaceType type, 118677143bbSMatt Spinler std::experimental::any& object) 119677143bbSMatt Spinler { 120677143bbSMatt Spinler auto id = getEntryID(objectPath); 121677143bbSMatt Spinler auto entry = childEntries.find(id); 122677143bbSMatt Spinler 123677143bbSMatt Spinler // childEntries is: 124677143bbSMatt Spinler // A map of error log entry IDs to: 125677143bbSMatt Spinler // a map of interface types to: 126677143bbSMatt Spinler // a vector of interface objects 127677143bbSMatt Spinler 128677143bbSMatt Spinler if (entry == childEntries.end()) 129677143bbSMatt Spinler { 130677143bbSMatt Spinler ObjectList objects{object}; 131677143bbSMatt Spinler InterfaceMapMulti interfaces; 132677143bbSMatt Spinler interfaces.emplace(type, std::move(objects)); 133677143bbSMatt Spinler childEntries.emplace(id, std::move(interfaces)); 134677143bbSMatt Spinler } 135677143bbSMatt Spinler else 136677143bbSMatt Spinler { 137677143bbSMatt Spinler auto i = entry->second.find(type); 138677143bbSMatt Spinler if (i == entry->second.end()) 139677143bbSMatt Spinler { 140677143bbSMatt Spinler ObjectList objects{objects}; 141677143bbSMatt Spinler entry->second.emplace(type, objects); 142677143bbSMatt Spinler } 143677143bbSMatt Spinler else 144677143bbSMatt Spinler { 145677143bbSMatt Spinler i->second.emplace_back(object); 146677143bbSMatt Spinler } 147677143bbSMatt Spinler } 148677143bbSMatt Spinler } 149677143bbSMatt Spinler 1504a6ea6afSMatt Spinler #ifdef USE_POLICY_INTERFACE 151259e7277SMatt Spinler void Manager::createPolicyInterface(const std::string& objectPath, 1524a6ea6afSMatt Spinler const DbusPropertyMap& properties) 1534a6ea6afSMatt Spinler { 1544a6ea6afSMatt Spinler auto values = policy::find(policies, properties); 1554a6ea6afSMatt Spinler 156259e7277SMatt Spinler auto object = std::make_shared<PolicyObject>(bus, objectPath.c_str(), true); 1574a6ea6afSMatt Spinler 1584a6ea6afSMatt Spinler object->eventID(std::get<policy::EIDField>(values)); 1594a6ea6afSMatt Spinler object->description(std::get<policy::MsgField>(values)); 1604a6ea6afSMatt Spinler 1619bea4eafSMatt Spinler object->emit_object_added(); 1629bea4eafSMatt Spinler 163491fc6f1SMatt Spinler std::experimental::any anyObject = object; 1644a6ea6afSMatt Spinler 165491fc6f1SMatt Spinler addInterface(objectPath, InterfaceType::POLICY, anyObject); 1664a6ea6afSMatt Spinler } 1674a6ea6afSMatt Spinler #endif 1684a6ea6afSMatt Spinler 169*52ee71bdSMatt Spinler void Manager::createCalloutObjects(const std::string& objectPath, 170*52ee71bdSMatt Spinler const DbusInterfaceMap& interfaces) 171*52ee71bdSMatt Spinler { 172*52ee71bdSMatt Spinler // Use the associations property in the org.openbmc.Associations 173*52ee71bdSMatt Spinler // interface to find any callouts. Then grab all properties on 174*52ee71bdSMatt Spinler // the Asset interface for that object in the inventory to use 175*52ee71bdSMatt Spinler // in our callout objects. 176*52ee71bdSMatt Spinler 177*52ee71bdSMatt Spinler auto associations = interfaces.find(ASSOC_IFACE); 178*52ee71bdSMatt Spinler if (associations == interfaces.end()) 179*52ee71bdSMatt Spinler { 180*52ee71bdSMatt Spinler return; 181*52ee71bdSMatt Spinler } 182*52ee71bdSMatt Spinler 183*52ee71bdSMatt Spinler const auto& properties = associations->second; 184*52ee71bdSMatt Spinler auto assocProperty = properties.find("associations"); 185*52ee71bdSMatt Spinler auto assocValue = assocProperty->second.get<AssociationsPropertyType>(); 186*52ee71bdSMatt Spinler 187*52ee71bdSMatt Spinler auto id = getEntryID(objectPath); 188*52ee71bdSMatt Spinler auto calloutNum = 0; 189*52ee71bdSMatt Spinler DbusSubtree subtree; 190*52ee71bdSMatt Spinler 191*52ee71bdSMatt Spinler for (const auto& association : assocValue) 192*52ee71bdSMatt Spinler { 193*52ee71bdSMatt Spinler if (std::get<forwardPos>(association) != "callout") 194*52ee71bdSMatt Spinler { 195*52ee71bdSMatt Spinler continue; 196*52ee71bdSMatt Spinler } 197*52ee71bdSMatt Spinler 198*52ee71bdSMatt Spinler auto callout = std::get<endpointPos>(association); 199*52ee71bdSMatt Spinler 200*52ee71bdSMatt Spinler if (subtree.empty()) 201*52ee71bdSMatt Spinler { 202*52ee71bdSMatt Spinler subtree = getSubtree(bus, "/", 0, ASSET_IFACE); 203*52ee71bdSMatt Spinler if (subtree.empty()) 204*52ee71bdSMatt Spinler { 205*52ee71bdSMatt Spinler break; 206*52ee71bdSMatt Spinler } 207*52ee71bdSMatt Spinler } 208*52ee71bdSMatt Spinler 209*52ee71bdSMatt Spinler auto service = getService(callout, ASSET_IFACE, subtree); 210*52ee71bdSMatt Spinler if (service.empty()) 211*52ee71bdSMatt Spinler { 212*52ee71bdSMatt Spinler continue; 213*52ee71bdSMatt Spinler } 214*52ee71bdSMatt Spinler 215*52ee71bdSMatt Spinler auto properties = getAllProperties(bus, service, callout, ASSET_IFACE); 216*52ee71bdSMatt Spinler if (properties.empty()) 217*52ee71bdSMatt Spinler { 218*52ee71bdSMatt Spinler continue; 219*52ee71bdSMatt Spinler } 220*52ee71bdSMatt Spinler 221*52ee71bdSMatt Spinler auto calloutPath = getCalloutObjectPath(objectPath, calloutNum); 222*52ee71bdSMatt Spinler 223*52ee71bdSMatt Spinler auto object = 224*52ee71bdSMatt Spinler std::make_shared<Callout>(bus, calloutPath, callout, calloutNum, 225*52ee71bdSMatt Spinler getLogTimestamp(interfaces), properties); 226*52ee71bdSMatt Spinler 227*52ee71bdSMatt Spinler auto dir = getCalloutSaveDir(id); 228*52ee71bdSMatt Spinler if (!fs::exists(dir)) 229*52ee71bdSMatt Spinler { 230*52ee71bdSMatt Spinler fs::create_directories(dir); 231*52ee71bdSMatt Spinler } 232*52ee71bdSMatt Spinler object->serialize(dir); 233*52ee71bdSMatt Spinler 234*52ee71bdSMatt Spinler std::experimental::any anyObject = object; 235*52ee71bdSMatt Spinler addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject); 236*52ee71bdSMatt Spinler calloutNum++; 237*52ee71bdSMatt Spinler } 238*52ee71bdSMatt Spinler } 239*52ee71bdSMatt Spinler 240e0017ebbSMatt Spinler void Manager::interfaceAdded(sdbusplus::message::message& msg) 241e0017ebbSMatt Spinler { 242e0017ebbSMatt Spinler sdbusplus::message::object_path path; 243e0017ebbSMatt Spinler DbusInterfaceMap interfaces; 244e0017ebbSMatt Spinler 245e0017ebbSMatt Spinler msg.read(path, interfaces); 246e0017ebbSMatt Spinler 247e0017ebbSMatt Spinler // Find the Logging.Entry interface with all of its properties 248e0017ebbSMatt Spinler // to pass to create(). 249e6a51590SMatt Spinler if (interfaces.find(LOGGING_IFACE) != interfaces.end()) 250e0017ebbSMatt Spinler { 251e6a51590SMatt Spinler create(path, interfaces); 252e0017ebbSMatt Spinler } 253e0017ebbSMatt Spinler } 254055da3bdSMatt Spinler 255*52ee71bdSMatt Spinler uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces) 256*52ee71bdSMatt Spinler { 257*52ee71bdSMatt Spinler auto interface = interfaces.find(LOGGING_IFACE); 258*52ee71bdSMatt Spinler if (interface != interfaces.end()) 259*52ee71bdSMatt Spinler { 260*52ee71bdSMatt Spinler auto property = interface->second.find("Timestamp"); 261*52ee71bdSMatt Spinler if (property != interface->second.end()) 262*52ee71bdSMatt Spinler { 263*52ee71bdSMatt Spinler return property->second.get<uint64_t>(); 264*52ee71bdSMatt Spinler } 265*52ee71bdSMatt Spinler } 266*52ee71bdSMatt Spinler 267*52ee71bdSMatt Spinler return 0; 268*52ee71bdSMatt Spinler } 269*52ee71bdSMatt Spinler 270*52ee71bdSMatt Spinler fs::path Manager::getSaveDir(EntryID id) 271*52ee71bdSMatt Spinler { 272*52ee71bdSMatt Spinler return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id); 273*52ee71bdSMatt Spinler } 274*52ee71bdSMatt Spinler 275*52ee71bdSMatt Spinler fs::path Manager::getCalloutSaveDir(EntryID id) 276*52ee71bdSMatt Spinler { 277*52ee71bdSMatt Spinler return getSaveDir(id) / "callouts"; 278*52ee71bdSMatt Spinler } 279*52ee71bdSMatt Spinler 280*52ee71bdSMatt Spinler std::string Manager::getCalloutObjectPath(const std::string& objectPath, 281*52ee71bdSMatt Spinler uint32_t calloutNum) 282*52ee71bdSMatt Spinler { 283*52ee71bdSMatt Spinler return fs::path{objectPath} / "callouts" / std::to_string(calloutNum); 284*52ee71bdSMatt Spinler } 285*52ee71bdSMatt Spinler 286055da3bdSMatt Spinler void Manager::interfaceRemoved(sdbusplus::message::message& msg) 287055da3bdSMatt Spinler { 288055da3bdSMatt Spinler sdbusplus::message::object_path path; 289055da3bdSMatt Spinler DbusInterfaceList interfaces; 290055da3bdSMatt Spinler 291055da3bdSMatt Spinler msg.read(path, interfaces); 292055da3bdSMatt Spinler 293055da3bdSMatt Spinler // If the Logging.Entry interface was removed, then remove 294055da3bdSMatt Spinler // our object 295055da3bdSMatt Spinler 296055da3bdSMatt Spinler auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE); 297055da3bdSMatt Spinler 298055da3bdSMatt Spinler if (i != interfaces.end()) 299055da3bdSMatt Spinler { 300a1390353SMatt Spinler erase(getEntryID(path)); 301055da3bdSMatt Spinler } 302055da3bdSMatt Spinler } 303e0017ebbSMatt Spinler } 304e0017ebbSMatt Spinler } 305