xref: /openbmc/ibm-logging/manager.cpp (revision 6a2b8956)
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  */
16e0017ebbSMatt Spinler #include "config.h"
1766e07073SMatt Spinler 
18e0017ebbSMatt Spinler #include "manager.hpp"
1966e07073SMatt Spinler 
2066e07073SMatt Spinler #include "callout.hpp"
214a6ea6afSMatt Spinler #include "policy_find.hpp"
22e0017ebbSMatt Spinler 
2366e07073SMatt Spinler #include <phosphor-logging/log.hpp>
2466e07073SMatt Spinler 
25e0017ebbSMatt Spinler namespace ibm
26e0017ebbSMatt Spinler {
27e0017ebbSMatt Spinler namespace logging
28e0017ebbSMatt Spinler {
29e0017ebbSMatt Spinler 
3052ee71bdSMatt Spinler namespace fs = std::experimental::filesystem;
3134af47ffSMatt Spinler using namespace phosphor::logging;
3252ee71bdSMatt Spinler 
Manager(sdbusplus::bus_t & bus)338123a713SPatrick Williams Manager::Manager(sdbusplus::bus_t& bus) :
34e0017ebbSMatt Spinler     bus(bus),
35259e7277SMatt Spinler     addMatch(bus,
36e0017ebbSMatt Spinler              sdbusplus::bus::match::rules::interfacesAdded() +
37e0017ebbSMatt Spinler                  sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
38259e7277SMatt Spinler              std::bind(std::mem_fn(&Manager::interfaceAdded), this,
39055da3bdSMatt Spinler                        std::placeholders::_1)),
40055da3bdSMatt Spinler     removeMatch(bus,
41055da3bdSMatt Spinler                 sdbusplus::bus::match::rules::interfacesRemoved() +
42055da3bdSMatt Spinler                     sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
43055da3bdSMatt Spinler                 std::bind(std::mem_fn(&Manager::interfaceRemoved), this,
44259e7277SMatt Spinler                           std::placeholders::_1))
45743e5822SMatt Spinler #ifdef USE_POLICY_INTERFACE
46259e7277SMatt Spinler     ,
47259e7277SMatt Spinler     policies(POLICY_JSON_PATH)
48743e5822SMatt Spinler #endif
49e0017ebbSMatt Spinler {
5054bfa7e7SMatt Spinler     createAll();
5154bfa7e7SMatt Spinler }
5254bfa7e7SMatt Spinler 
createAll()5354bfa7e7SMatt Spinler void Manager::createAll()
5454bfa7e7SMatt Spinler {
5534af47ffSMatt Spinler     try
5634af47ffSMatt Spinler     {
57259e7277SMatt Spinler         auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH);
5854bfa7e7SMatt Spinler 
5954bfa7e7SMatt Spinler         for (const auto& object : objects)
6054bfa7e7SMatt Spinler         {
6154bfa7e7SMatt Spinler             const auto& interfaces = object.second;
6254bfa7e7SMatt Spinler 
63e6a51590SMatt Spinler             auto propertyMap = interfaces.find(LOGGING_IFACE);
6454bfa7e7SMatt Spinler 
6554bfa7e7SMatt Spinler             if (propertyMap != interfaces.end())
6654bfa7e7SMatt Spinler             {
67e6a51590SMatt Spinler                 createWithRestore(object.first, interfaces);
6854bfa7e7SMatt Spinler             }
6954bfa7e7SMatt Spinler         }
7054bfa7e7SMatt Spinler     }
718123a713SPatrick Williams     catch (const sdbusplus::exception_t& e)
7234af47ffSMatt Spinler     {
7334af47ffSMatt Spinler         log<level::ERR>("sdbusplus error getting logging managed objects",
7434af47ffSMatt Spinler                         entry("ERROR=%s", e.what()));
7534af47ffSMatt Spinler     }
7634af47ffSMatt Spinler }
7754bfa7e7SMatt Spinler 
createWithRestore(const std::string & objectPath,const DbusInterfaceMap & interfaces)78e6a51590SMatt Spinler void Manager::createWithRestore(const std::string& objectPath,
79e6a51590SMatt Spinler                                 const DbusInterfaceMap& interfaces)
80e6a51590SMatt Spinler {
81e6a51590SMatt Spinler     createObject(objectPath, interfaces);
82e6a51590SMatt Spinler 
8360f53d86SMatt Spinler     restoreCalloutObjects(objectPath, interfaces);
84e6a51590SMatt Spinler }
85e6a51590SMatt Spinler 
create(const std::string & objectPath,const DbusInterfaceMap & interfaces)86259e7277SMatt Spinler void Manager::create(const std::string& objectPath,
87e6a51590SMatt Spinler                      const DbusInterfaceMap& interfaces)
8854bfa7e7SMatt Spinler {
89e6a51590SMatt Spinler     createObject(objectPath, interfaces);
904a6ea6afSMatt Spinler 
9152ee71bdSMatt Spinler     createCalloutObjects(objectPath, interfaces);
92e6a51590SMatt Spinler }
93e6a51590SMatt Spinler 
createObject(const std::string & objectPath,const DbusInterfaceMap & interfaces)94e6a51590SMatt Spinler void Manager::createObject(const std::string& objectPath,
95e6a51590SMatt Spinler                            const DbusInterfaceMap& interfaces)
96e6a51590SMatt Spinler {
974a6ea6afSMatt Spinler #ifdef USE_POLICY_INTERFACE
98e6a51590SMatt Spinler     auto logInterface = interfaces.find(LOGGING_IFACE);
99e6a51590SMatt Spinler     createPolicyInterface(objectPath, logInterface->second);
1004a6ea6afSMatt Spinler #endif
101e0017ebbSMatt Spinler }
102e0017ebbSMatt Spinler 
erase(EntryID id)103a1390353SMatt Spinler void Manager::erase(EntryID id)
104a1390353SMatt Spinler {
10552ee71bdSMatt Spinler     fs::remove_all(getSaveDir(id));
106677143bbSMatt Spinler     childEntries.erase(id);
107a1390353SMatt Spinler     entries.erase(id);
108a1390353SMatt Spinler }
109a1390353SMatt Spinler 
addInterface(const std::string & objectPath,InterfaceType type,std::any & object)110491fc6f1SMatt Spinler void Manager::addInterface(const std::string& objectPath, InterfaceType type,
11154ea3ad8SMatt Spinler                            std::any& object)
112491fc6f1SMatt Spinler {
113491fc6f1SMatt Spinler     auto id = getEntryID(objectPath);
114491fc6f1SMatt Spinler     auto entry = entries.find(id);
115491fc6f1SMatt Spinler 
116491fc6f1SMatt Spinler     if (entry == entries.end())
117491fc6f1SMatt Spinler     {
118491fc6f1SMatt Spinler         InterfaceMap interfaces;
119491fc6f1SMatt Spinler         interfaces.emplace(type, object);
120491fc6f1SMatt Spinler         entries.emplace(id, std::move(interfaces));
121491fc6f1SMatt Spinler     }
122491fc6f1SMatt Spinler     else
123491fc6f1SMatt Spinler     {
124491fc6f1SMatt Spinler         entry->second.emplace(type, object);
125491fc6f1SMatt Spinler     }
126491fc6f1SMatt Spinler }
127491fc6f1SMatt Spinler 
addChildInterface(const std::string & objectPath,InterfaceType type,std::any & object)128677143bbSMatt Spinler void Manager::addChildInterface(const std::string& objectPath,
12954ea3ad8SMatt Spinler                                 InterfaceType type, std::any& object)
130677143bbSMatt Spinler {
131677143bbSMatt Spinler     auto id = getEntryID(objectPath);
132677143bbSMatt Spinler     auto entry = childEntries.find(id);
133677143bbSMatt Spinler 
134677143bbSMatt Spinler     // childEntries is:
135677143bbSMatt Spinler     // A map of error log entry IDs to:
136677143bbSMatt Spinler     //  a map of interface types to:
137677143bbSMatt Spinler     //    a vector of interface objects
138677143bbSMatt Spinler 
139677143bbSMatt Spinler     if (entry == childEntries.end())
140677143bbSMatt Spinler     {
141677143bbSMatt Spinler         ObjectList objects{object};
142677143bbSMatt Spinler         InterfaceMapMulti interfaces;
143677143bbSMatt Spinler         interfaces.emplace(type, std::move(objects));
144677143bbSMatt Spinler         childEntries.emplace(id, std::move(interfaces));
145677143bbSMatt Spinler     }
146677143bbSMatt Spinler     else
147677143bbSMatt Spinler     {
148677143bbSMatt Spinler         auto i = entry->second.find(type);
149677143bbSMatt Spinler         if (i == entry->second.end())
150677143bbSMatt Spinler         {
1511b388099SMatt Spinler             ObjectList objects{object};
152677143bbSMatt Spinler             entry->second.emplace(type, objects);
153677143bbSMatt Spinler         }
154677143bbSMatt Spinler         else
155677143bbSMatt Spinler         {
156677143bbSMatt Spinler             i->second.emplace_back(object);
157677143bbSMatt Spinler         }
158677143bbSMatt Spinler     }
159677143bbSMatt Spinler }
160677143bbSMatt Spinler 
1614a6ea6afSMatt Spinler #ifdef USE_POLICY_INTERFACE
createPolicyInterface(const std::string & objectPath,const DbusPropertyMap & properties)162259e7277SMatt Spinler void Manager::createPolicyInterface(const std::string& objectPath,
1634a6ea6afSMatt Spinler                                     const DbusPropertyMap& properties)
1644a6ea6afSMatt Spinler {
1654a6ea6afSMatt Spinler     auto values = policy::find(policies, properties);
1664a6ea6afSMatt Spinler 
167c0763620SPatrick Williams     auto object = std::make_shared<PolicyObject>(
168c0763620SPatrick Williams         bus, objectPath.c_str(), PolicyObject::action::defer_emit);
1694a6ea6afSMatt Spinler 
1704a6ea6afSMatt Spinler     object->eventID(std::get<policy::EIDField>(values));
1714a6ea6afSMatt Spinler     object->description(std::get<policy::MsgField>(values));
1724a6ea6afSMatt Spinler 
1739bea4eafSMatt Spinler     object->emit_object_added();
1749bea4eafSMatt Spinler 
17554ea3ad8SMatt Spinler     std::any anyObject = object;
1764a6ea6afSMatt Spinler 
177491fc6f1SMatt Spinler     addInterface(objectPath, InterfaceType::POLICY, anyObject);
1784a6ea6afSMatt Spinler }
1794a6ea6afSMatt Spinler #endif
1804a6ea6afSMatt Spinler 
createCalloutObjects(const std::string & objectPath,const DbusInterfaceMap & interfaces)18152ee71bdSMatt Spinler void Manager::createCalloutObjects(const std::string& objectPath,
18252ee71bdSMatt Spinler                                    const DbusInterfaceMap& interfaces)
18352ee71bdSMatt Spinler {
18452ee71bdSMatt Spinler     // Use the associations property in the org.openbmc.Associations
18552ee71bdSMatt Spinler     // interface to find any callouts.  Then grab all properties on
18652ee71bdSMatt Spinler     // the Asset interface for that object in the inventory to use
18752ee71bdSMatt Spinler     // in our callout objects.
18852ee71bdSMatt Spinler 
18952ee71bdSMatt Spinler     auto associations = interfaces.find(ASSOC_IFACE);
19052ee71bdSMatt Spinler     if (associations == interfaces.end())
19152ee71bdSMatt Spinler     {
19252ee71bdSMatt Spinler         return;
19352ee71bdSMatt Spinler     }
19452ee71bdSMatt Spinler 
19552ee71bdSMatt Spinler     const auto& properties = associations->second;
1964c0e8945SMatt Spinler     auto assocProperty = properties.find("Associations");
197b5af3a3fSPatrick Williams     auto assocValue = std::get<AssociationsPropertyType>(assocProperty->second);
19852ee71bdSMatt Spinler 
19952ee71bdSMatt Spinler     auto id = getEntryID(objectPath);
20052ee71bdSMatt Spinler     auto calloutNum = 0;
20152ee71bdSMatt Spinler     DbusSubtree subtree;
20252ee71bdSMatt Spinler 
20352ee71bdSMatt Spinler     for (const auto& association : assocValue)
20452ee71bdSMatt Spinler     {
20534af47ffSMatt Spinler         try
20634af47ffSMatt Spinler         {
20752ee71bdSMatt Spinler             if (std::get<forwardPos>(association) != "callout")
20852ee71bdSMatt Spinler             {
20952ee71bdSMatt Spinler                 continue;
21052ee71bdSMatt Spinler             }
21152ee71bdSMatt Spinler 
21252ee71bdSMatt Spinler             auto callout = std::get<endpointPos>(association);
21352ee71bdSMatt Spinler 
21452ee71bdSMatt Spinler             if (subtree.empty())
21552ee71bdSMatt Spinler             {
21652ee71bdSMatt Spinler                 subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
21752ee71bdSMatt Spinler                 if (subtree.empty())
21852ee71bdSMatt Spinler                 {
21952ee71bdSMatt Spinler                     break;
22052ee71bdSMatt Spinler                 }
22152ee71bdSMatt Spinler             }
22252ee71bdSMatt Spinler 
22352ee71bdSMatt Spinler             auto service = getService(callout, ASSET_IFACE, subtree);
22452ee71bdSMatt Spinler             if (service.empty())
22552ee71bdSMatt Spinler             {
22652ee71bdSMatt Spinler                 continue;
22752ee71bdSMatt Spinler             }
22852ee71bdSMatt Spinler 
229*6a2b8956SPatrick Williams             auto properties = getAllProperties(bus, service, callout,
230*6a2b8956SPatrick Williams                                                ASSET_IFACE);
23152ee71bdSMatt Spinler             if (properties.empty())
23252ee71bdSMatt Spinler             {
23352ee71bdSMatt Spinler                 continue;
23452ee71bdSMatt Spinler             }
23552ee71bdSMatt Spinler 
23652ee71bdSMatt Spinler             auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
23752ee71bdSMatt Spinler 
23834af47ffSMatt Spinler             auto object = std::make_shared<Callout>(
23934af47ffSMatt Spinler                 bus, calloutPath, callout, calloutNum,
24052ee71bdSMatt Spinler                 getLogTimestamp(interfaces), properties);
24152ee71bdSMatt Spinler 
24252ee71bdSMatt Spinler             auto dir = getCalloutSaveDir(id);
24352ee71bdSMatt Spinler             if (!fs::exists(dir))
24452ee71bdSMatt Spinler             {
24552ee71bdSMatt Spinler                 fs::create_directories(dir);
24652ee71bdSMatt Spinler             }
24752ee71bdSMatt Spinler             object->serialize(dir);
24852ee71bdSMatt Spinler 
24954ea3ad8SMatt Spinler             std::any anyObject = object;
25052ee71bdSMatt Spinler             addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
25152ee71bdSMatt Spinler             calloutNum++;
25252ee71bdSMatt Spinler         }
2538123a713SPatrick Williams         catch (const sdbusplus::exception_t& e)
25434af47ffSMatt Spinler         {
25534af47ffSMatt Spinler             log<level::ERR>("sdbusplus exception", entry("ERROR=%s", e.what()));
25634af47ffSMatt Spinler         }
25734af47ffSMatt Spinler     }
25852ee71bdSMatt Spinler }
25952ee71bdSMatt Spinler 
restoreCalloutObjects(const std::string & objectPath,const DbusInterfaceMap & interfaces)26060f53d86SMatt Spinler void Manager::restoreCalloutObjects(const std::string& objectPath,
26160f53d86SMatt Spinler                                     const DbusInterfaceMap& interfaces)
26260f53d86SMatt Spinler {
26360f53d86SMatt Spinler     auto saveDir = getCalloutSaveDir(getEntryID(objectPath));
26460f53d86SMatt Spinler 
26560f53d86SMatt Spinler     if (!fs::exists(saveDir))
26660f53d86SMatt Spinler     {
26760f53d86SMatt Spinler         return;
26860f53d86SMatt Spinler     }
26960f53d86SMatt Spinler 
27060f53d86SMatt Spinler     size_t id;
27160f53d86SMatt Spinler     for (auto& f : fs::directory_iterator(saveDir))
27260f53d86SMatt Spinler     {
27360f53d86SMatt Spinler         try
27460f53d86SMatt Spinler         {
27560f53d86SMatt Spinler             id = std::stoul(f.path().filename());
27660f53d86SMatt Spinler         }
277bf9ea8adSPatrick Williams         catch (const std::exception& e)
27860f53d86SMatt Spinler         {
27960f53d86SMatt Spinler             log<level::ERR>("Invalid IBM logging callout save file. Deleting",
28060f53d86SMatt Spinler                             entry("FILE=%s", f.path().c_str()));
28160f53d86SMatt Spinler             fs::remove(f.path());
28260f53d86SMatt Spinler             continue;
28360f53d86SMatt Spinler         }
28460f53d86SMatt Spinler 
28560f53d86SMatt Spinler         auto path = getCalloutObjectPath(objectPath, id);
28660f53d86SMatt Spinler         auto callout = std::make_shared<Callout>(bus, path, id,
28760f53d86SMatt Spinler                                                  getLogTimestamp(interfaces));
28860f53d86SMatt Spinler         if (callout->deserialize(saveDir))
28960f53d86SMatt Spinler         {
29060f53d86SMatt Spinler             callout->emit_object_added();
29154ea3ad8SMatt Spinler             std::any anyObject = callout;
29260f53d86SMatt Spinler             addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
29360f53d86SMatt Spinler         }
29460f53d86SMatt Spinler     }
29560f53d86SMatt Spinler }
29660f53d86SMatt Spinler 
interfaceAdded(sdbusplus::message_t & msg)2978123a713SPatrick Williams void Manager::interfaceAdded(sdbusplus::message_t& msg)
298e0017ebbSMatt Spinler {
299e0017ebbSMatt Spinler     sdbusplus::message::object_path path;
300e0017ebbSMatt Spinler     DbusInterfaceMap interfaces;
301e0017ebbSMatt Spinler 
302e0017ebbSMatt Spinler     msg.read(path, interfaces);
303e0017ebbSMatt Spinler 
304e0017ebbSMatt Spinler     // Find the Logging.Entry interface with all of its properties
305e0017ebbSMatt Spinler     // to pass to create().
306e6a51590SMatt Spinler     if (interfaces.find(LOGGING_IFACE) != interfaces.end())
307e0017ebbSMatt Spinler     {
308e6a51590SMatt Spinler         create(path, interfaces);
309e0017ebbSMatt Spinler     }
310e0017ebbSMatt Spinler }
311055da3bdSMatt Spinler 
getLogTimestamp(const DbusInterfaceMap & interfaces)31252ee71bdSMatt Spinler uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
31352ee71bdSMatt Spinler {
31452ee71bdSMatt Spinler     auto interface = interfaces.find(LOGGING_IFACE);
31552ee71bdSMatt Spinler     if (interface != interfaces.end())
31652ee71bdSMatt Spinler     {
31752ee71bdSMatt Spinler         auto property = interface->second.find("Timestamp");
31852ee71bdSMatt Spinler         if (property != interface->second.end())
31952ee71bdSMatt Spinler         {
320b5af3a3fSPatrick Williams             return std::get<uint64_t>(property->second);
32152ee71bdSMatt Spinler         }
32252ee71bdSMatt Spinler     }
32352ee71bdSMatt Spinler 
32452ee71bdSMatt Spinler     return 0;
32552ee71bdSMatt Spinler }
32652ee71bdSMatt Spinler 
getSaveDir(EntryID id)32752ee71bdSMatt Spinler fs::path Manager::getSaveDir(EntryID id)
32852ee71bdSMatt Spinler {
32952ee71bdSMatt Spinler     return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
33052ee71bdSMatt Spinler }
33152ee71bdSMatt Spinler 
getCalloutSaveDir(EntryID id)33252ee71bdSMatt Spinler fs::path Manager::getCalloutSaveDir(EntryID id)
33352ee71bdSMatt Spinler {
33452ee71bdSMatt Spinler     return getSaveDir(id) / "callouts";
33552ee71bdSMatt Spinler }
33652ee71bdSMatt Spinler 
getCalloutObjectPath(const std::string & objectPath,uint32_t calloutNum)33752ee71bdSMatt Spinler std::string Manager::getCalloutObjectPath(const std::string& objectPath,
33852ee71bdSMatt Spinler                                           uint32_t calloutNum)
33952ee71bdSMatt Spinler {
34052ee71bdSMatt Spinler     return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
34152ee71bdSMatt Spinler }
34252ee71bdSMatt Spinler 
interfaceRemoved(sdbusplus::message_t & msg)3438123a713SPatrick Williams void Manager::interfaceRemoved(sdbusplus::message_t& msg)
344055da3bdSMatt Spinler {
345055da3bdSMatt Spinler     sdbusplus::message::object_path path;
346055da3bdSMatt Spinler     DbusInterfaceList interfaces;
347055da3bdSMatt Spinler 
348055da3bdSMatt Spinler     msg.read(path, interfaces);
349055da3bdSMatt Spinler 
350055da3bdSMatt Spinler     // If the Logging.Entry interface was removed, then remove
351055da3bdSMatt Spinler     // our object
352055da3bdSMatt Spinler 
353055da3bdSMatt Spinler     auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE);
354055da3bdSMatt Spinler 
355055da3bdSMatt Spinler     if (i != interfaces.end())
356055da3bdSMatt Spinler     {
357a1390353SMatt Spinler         erase(getEntryID(path));
358055da3bdSMatt Spinler     }
359055da3bdSMatt Spinler }
36066e07073SMatt Spinler } // namespace logging
36166e07073SMatt Spinler } // namespace ibm
362