xref: /openbmc/ibm-logging/manager.cpp (revision 52ee71bd)
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