xref: /openbmc/ibm-logging/manager.cpp (revision 60f53d86)
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*60f53d86SMatt Spinler #include <phosphor-logging/log.hpp>
1752ee71bdSMatt Spinler #include "callout.hpp"
18e0017ebbSMatt Spinler #include "config.h"
19e0017ebbSMatt Spinler #include "manager.hpp"
204a6ea6afSMatt Spinler #include "policy_find.hpp"
21e0017ebbSMatt Spinler 
22e0017ebbSMatt Spinler namespace ibm
23e0017ebbSMatt Spinler {
24e0017ebbSMatt Spinler namespace logging
25e0017ebbSMatt Spinler {
26e0017ebbSMatt Spinler 
2752ee71bdSMatt Spinler namespace fs = std::experimental::filesystem;
2852ee71bdSMatt Spinler 
29e0017ebbSMatt Spinler Manager::Manager(sdbusplus::bus::bus& bus) :
30e0017ebbSMatt Spinler     bus(bus),
31259e7277SMatt Spinler     addMatch(bus,
32e0017ebbSMatt Spinler              sdbusplus::bus::match::rules::interfacesAdded() +
33e0017ebbSMatt Spinler                  sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
34259e7277SMatt Spinler              std::bind(std::mem_fn(&Manager::interfaceAdded), this,
35055da3bdSMatt Spinler                        std::placeholders::_1)),
36055da3bdSMatt Spinler     removeMatch(bus,
37055da3bdSMatt Spinler                 sdbusplus::bus::match::rules::interfacesRemoved() +
38055da3bdSMatt Spinler                     sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
39055da3bdSMatt Spinler                 std::bind(std::mem_fn(&Manager::interfaceRemoved), this,
40259e7277SMatt Spinler                           std::placeholders::_1))
41743e5822SMatt Spinler #ifdef USE_POLICY_INTERFACE
42259e7277SMatt Spinler     ,
43259e7277SMatt Spinler     policies(POLICY_JSON_PATH)
44743e5822SMatt Spinler #endif
45e0017ebbSMatt Spinler {
4654bfa7e7SMatt Spinler     createAll();
4754bfa7e7SMatt Spinler }
4854bfa7e7SMatt Spinler 
4954bfa7e7SMatt Spinler void Manager::createAll()
5054bfa7e7SMatt Spinler {
51259e7277SMatt Spinler     auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH);
5254bfa7e7SMatt Spinler 
5354bfa7e7SMatt Spinler     for (const auto& object : objects)
5454bfa7e7SMatt Spinler     {
5554bfa7e7SMatt Spinler         const auto& interfaces = object.second;
5654bfa7e7SMatt Spinler 
57e6a51590SMatt Spinler         auto propertyMap = interfaces.find(LOGGING_IFACE);
5854bfa7e7SMatt Spinler 
5954bfa7e7SMatt Spinler         if (propertyMap != interfaces.end())
6054bfa7e7SMatt Spinler         {
61e6a51590SMatt Spinler             createWithRestore(object.first, interfaces);
6254bfa7e7SMatt Spinler         }
6354bfa7e7SMatt Spinler     }
6454bfa7e7SMatt Spinler }
6554bfa7e7SMatt Spinler 
66e6a51590SMatt Spinler void Manager::createWithRestore(const std::string& objectPath,
67e6a51590SMatt Spinler                                 const DbusInterfaceMap& interfaces)
68e6a51590SMatt Spinler {
69e6a51590SMatt Spinler     createObject(objectPath, interfaces);
70e6a51590SMatt Spinler 
71*60f53d86SMatt 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 
7952ee71bdSMatt 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 {
9352ee71bdSMatt 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 
16952ee71bdSMatt Spinler void Manager::createCalloutObjects(const std::string& objectPath,
17052ee71bdSMatt Spinler                                    const DbusInterfaceMap& interfaces)
17152ee71bdSMatt Spinler {
17252ee71bdSMatt Spinler     // Use the associations property in the org.openbmc.Associations
17352ee71bdSMatt Spinler     // interface to find any callouts.  Then grab all properties on
17452ee71bdSMatt Spinler     // the Asset interface for that object in the inventory to use
17552ee71bdSMatt Spinler     // in our callout objects.
17652ee71bdSMatt Spinler 
17752ee71bdSMatt Spinler     auto associations = interfaces.find(ASSOC_IFACE);
17852ee71bdSMatt Spinler     if (associations == interfaces.end())
17952ee71bdSMatt Spinler     {
18052ee71bdSMatt Spinler         return;
18152ee71bdSMatt Spinler     }
18252ee71bdSMatt Spinler 
18352ee71bdSMatt Spinler     const auto& properties = associations->second;
18452ee71bdSMatt Spinler     auto assocProperty = properties.find("associations");
18552ee71bdSMatt Spinler     auto assocValue = assocProperty->second.get<AssociationsPropertyType>();
18652ee71bdSMatt Spinler 
18752ee71bdSMatt Spinler     auto id = getEntryID(objectPath);
18852ee71bdSMatt Spinler     auto calloutNum = 0;
18952ee71bdSMatt Spinler     DbusSubtree subtree;
19052ee71bdSMatt Spinler 
19152ee71bdSMatt Spinler     for (const auto& association : assocValue)
19252ee71bdSMatt Spinler     {
19352ee71bdSMatt Spinler         if (std::get<forwardPos>(association) != "callout")
19452ee71bdSMatt Spinler         {
19552ee71bdSMatt Spinler             continue;
19652ee71bdSMatt Spinler         }
19752ee71bdSMatt Spinler 
19852ee71bdSMatt Spinler         auto callout = std::get<endpointPos>(association);
19952ee71bdSMatt Spinler 
20052ee71bdSMatt Spinler         if (subtree.empty())
20152ee71bdSMatt Spinler         {
20252ee71bdSMatt Spinler             subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
20352ee71bdSMatt Spinler             if (subtree.empty())
20452ee71bdSMatt Spinler             {
20552ee71bdSMatt Spinler                 break;
20652ee71bdSMatt Spinler             }
20752ee71bdSMatt Spinler         }
20852ee71bdSMatt Spinler 
20952ee71bdSMatt Spinler         auto service = getService(callout, ASSET_IFACE, subtree);
21052ee71bdSMatt Spinler         if (service.empty())
21152ee71bdSMatt Spinler         {
21252ee71bdSMatt Spinler             continue;
21352ee71bdSMatt Spinler         }
21452ee71bdSMatt Spinler 
21552ee71bdSMatt Spinler         auto properties = getAllProperties(bus, service, callout, ASSET_IFACE);
21652ee71bdSMatt Spinler         if (properties.empty())
21752ee71bdSMatt Spinler         {
21852ee71bdSMatt Spinler             continue;
21952ee71bdSMatt Spinler         }
22052ee71bdSMatt Spinler 
22152ee71bdSMatt Spinler         auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
22252ee71bdSMatt Spinler 
22352ee71bdSMatt Spinler         auto object =
22452ee71bdSMatt Spinler             std::make_shared<Callout>(bus, calloutPath, callout, calloutNum,
22552ee71bdSMatt Spinler                                       getLogTimestamp(interfaces), properties);
22652ee71bdSMatt Spinler 
22752ee71bdSMatt Spinler         auto dir = getCalloutSaveDir(id);
22852ee71bdSMatt Spinler         if (!fs::exists(dir))
22952ee71bdSMatt Spinler         {
23052ee71bdSMatt Spinler             fs::create_directories(dir);
23152ee71bdSMatt Spinler         }
23252ee71bdSMatt Spinler         object->serialize(dir);
23352ee71bdSMatt Spinler 
23452ee71bdSMatt Spinler         std::experimental::any anyObject = object;
23552ee71bdSMatt Spinler         addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
23652ee71bdSMatt Spinler         calloutNum++;
23752ee71bdSMatt Spinler     }
23852ee71bdSMatt Spinler }
23952ee71bdSMatt Spinler 
240*60f53d86SMatt Spinler void Manager::restoreCalloutObjects(const std::string& objectPath,
241*60f53d86SMatt Spinler                                     const DbusInterfaceMap& interfaces)
242*60f53d86SMatt Spinler {
243*60f53d86SMatt Spinler     auto saveDir = getCalloutSaveDir(getEntryID(objectPath));
244*60f53d86SMatt Spinler 
245*60f53d86SMatt Spinler     if (!fs::exists(saveDir))
246*60f53d86SMatt Spinler     {
247*60f53d86SMatt Spinler         return;
248*60f53d86SMatt Spinler     }
249*60f53d86SMatt Spinler 
250*60f53d86SMatt Spinler     size_t id;
251*60f53d86SMatt Spinler     for (auto& f : fs::directory_iterator(saveDir))
252*60f53d86SMatt Spinler     {
253*60f53d86SMatt Spinler         try
254*60f53d86SMatt Spinler         {
255*60f53d86SMatt Spinler             id = std::stoul(f.path().filename());
256*60f53d86SMatt Spinler         }
257*60f53d86SMatt Spinler         catch (std::exception& e)
258*60f53d86SMatt Spinler         {
259*60f53d86SMatt Spinler             using namespace phosphor::logging;
260*60f53d86SMatt Spinler             log<level::ERR>("Invalid IBM logging callout save file. Deleting",
261*60f53d86SMatt Spinler                             entry("FILE=%s", f.path().c_str()));
262*60f53d86SMatt Spinler             fs::remove(f.path());
263*60f53d86SMatt Spinler             continue;
264*60f53d86SMatt Spinler         }
265*60f53d86SMatt Spinler 
266*60f53d86SMatt Spinler         auto path = getCalloutObjectPath(objectPath, id);
267*60f53d86SMatt Spinler         auto callout = std::make_shared<Callout>(bus, path, id,
268*60f53d86SMatt Spinler                                                  getLogTimestamp(interfaces));
269*60f53d86SMatt Spinler         if (callout->deserialize(saveDir))
270*60f53d86SMatt Spinler         {
271*60f53d86SMatt Spinler             callout->emit_object_added();
272*60f53d86SMatt Spinler             std::experimental::any anyObject = callout;
273*60f53d86SMatt Spinler             addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
274*60f53d86SMatt Spinler         }
275*60f53d86SMatt Spinler     }
276*60f53d86SMatt Spinler }
277*60f53d86SMatt Spinler 
278e0017ebbSMatt Spinler void Manager::interfaceAdded(sdbusplus::message::message& msg)
279e0017ebbSMatt Spinler {
280e0017ebbSMatt Spinler     sdbusplus::message::object_path path;
281e0017ebbSMatt Spinler     DbusInterfaceMap interfaces;
282e0017ebbSMatt Spinler 
283e0017ebbSMatt Spinler     msg.read(path, interfaces);
284e0017ebbSMatt Spinler 
285e0017ebbSMatt Spinler     // Find the Logging.Entry interface with all of its properties
286e0017ebbSMatt Spinler     // to pass to create().
287e6a51590SMatt Spinler     if (interfaces.find(LOGGING_IFACE) != interfaces.end())
288e0017ebbSMatt Spinler     {
289e6a51590SMatt Spinler         create(path, interfaces);
290e0017ebbSMatt Spinler     }
291e0017ebbSMatt Spinler }
292055da3bdSMatt Spinler 
29352ee71bdSMatt Spinler uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
29452ee71bdSMatt Spinler {
29552ee71bdSMatt Spinler     auto interface = interfaces.find(LOGGING_IFACE);
29652ee71bdSMatt Spinler     if (interface != interfaces.end())
29752ee71bdSMatt Spinler     {
29852ee71bdSMatt Spinler         auto property = interface->second.find("Timestamp");
29952ee71bdSMatt Spinler         if (property != interface->second.end())
30052ee71bdSMatt Spinler         {
30152ee71bdSMatt Spinler             return property->second.get<uint64_t>();
30252ee71bdSMatt Spinler         }
30352ee71bdSMatt Spinler     }
30452ee71bdSMatt Spinler 
30552ee71bdSMatt Spinler     return 0;
30652ee71bdSMatt Spinler }
30752ee71bdSMatt Spinler 
30852ee71bdSMatt Spinler fs::path Manager::getSaveDir(EntryID id)
30952ee71bdSMatt Spinler {
31052ee71bdSMatt Spinler     return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
31152ee71bdSMatt Spinler }
31252ee71bdSMatt Spinler 
31352ee71bdSMatt Spinler fs::path Manager::getCalloutSaveDir(EntryID id)
31452ee71bdSMatt Spinler {
31552ee71bdSMatt Spinler     return getSaveDir(id) / "callouts";
31652ee71bdSMatt Spinler }
31752ee71bdSMatt Spinler 
31852ee71bdSMatt Spinler std::string Manager::getCalloutObjectPath(const std::string& objectPath,
31952ee71bdSMatt Spinler                                           uint32_t calloutNum)
32052ee71bdSMatt Spinler {
32152ee71bdSMatt Spinler     return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
32252ee71bdSMatt Spinler }
32352ee71bdSMatt Spinler 
324055da3bdSMatt Spinler void Manager::interfaceRemoved(sdbusplus::message::message& msg)
325055da3bdSMatt Spinler {
326055da3bdSMatt Spinler     sdbusplus::message::object_path path;
327055da3bdSMatt Spinler     DbusInterfaceList interfaces;
328055da3bdSMatt Spinler 
329055da3bdSMatt Spinler     msg.read(path, interfaces);
330055da3bdSMatt Spinler 
331055da3bdSMatt Spinler     // If the Logging.Entry interface was removed, then remove
332055da3bdSMatt Spinler     // our object
333055da3bdSMatt Spinler 
334055da3bdSMatt Spinler     auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE);
335055da3bdSMatt Spinler 
336055da3bdSMatt Spinler     if (i != interfaces.end())
337055da3bdSMatt Spinler     {
338a1390353SMatt Spinler         erase(getEntryID(path));
339055da3bdSMatt Spinler     }
340055da3bdSMatt Spinler }
341e0017ebbSMatt Spinler }
342e0017ebbSMatt Spinler }
343