blob: aa8d5e05ca00a56c4f11163b2d1877ca7678eda1 [file] [log] [blame]
Matt Spinlere0017eb2018-03-27 11:17:38 -05001/**
2 * Copyright © 2018 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "config.h"
Matt Spinler66e07072018-09-12 10:36:14 -050017
Matt Spinlere0017eb2018-03-27 11:17:38 -050018#include "manager.hpp"
Matt Spinler66e07072018-09-12 10:36:14 -050019
20#include "callout.hpp"
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050021#include "policy_find.hpp"
Matt Spinlere0017eb2018-03-27 11:17:38 -050022
Matt Spinler66e07072018-09-12 10:36:14 -050023#include <phosphor-logging/log.hpp>
24
Matt Spinlere0017eb2018-03-27 11:17:38 -050025namespace ibm
26{
27namespace logging
28{
29
Matt Spinler52ee71b2018-05-23 13:18:55 -050030namespace fs = std::experimental::filesystem;
Matt Spinler34af47f2018-07-16 14:07:03 -050031using namespace phosphor::logging;
Matt Spinler52ee71b2018-05-23 13:18:55 -050032
Matt Spinlere0017eb2018-03-27 11:17:38 -050033Manager::Manager(sdbusplus::bus::bus& bus) :
Matt Spinler259e7272018-03-29 10:57:17 -050034 bus(bus),
35 addMatch(bus,
36 sdbusplus::bus::match::rules::interfacesAdded() +
37 sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
38 std::bind(std::mem_fn(&Manager::interfaceAdded), this,
Matt Spinler055da3b2018-05-09 15:51:20 -050039 std::placeholders::_1)),
40 removeMatch(bus,
41 sdbusplus::bus::match::rules::interfacesRemoved() +
42 sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
43 std::bind(std::mem_fn(&Manager::interfaceRemoved), this,
44 std::placeholders::_1))
Matt Spinler743e5822018-03-27 13:44:50 -050045#ifdef USE_POLICY_INTERFACE
Matt Spinler259e7272018-03-29 10:57:17 -050046 ,
47 policies(POLICY_JSON_PATH)
Matt Spinler743e5822018-03-27 13:44:50 -050048#endif
Matt Spinlere0017eb2018-03-27 11:17:38 -050049{
Matt Spinler54bfa7e2018-03-27 11:28:59 -050050 createAll();
51}
52
53void Manager::createAll()
54{
Matt Spinler34af47f2018-07-16 14:07:03 -050055 try
Matt Spinler54bfa7e2018-03-27 11:28:59 -050056 {
Matt Spinler34af47f2018-07-16 14:07:03 -050057 auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH);
Matt Spinler54bfa7e2018-03-27 11:28:59 -050058
Matt Spinler34af47f2018-07-16 14:07:03 -050059 for (const auto& object : objects)
Matt Spinler54bfa7e2018-03-27 11:28:59 -050060 {
Matt Spinler34af47f2018-07-16 14:07:03 -050061 const auto& interfaces = object.second;
62
63 auto propertyMap = interfaces.find(LOGGING_IFACE);
64
65 if (propertyMap != interfaces.end())
66 {
67 createWithRestore(object.first, interfaces);
68 }
Matt Spinler54bfa7e2018-03-27 11:28:59 -050069 }
70 }
Matt Spinler1eb63672021-09-02 16:41:27 -050071 catch (const sdbusplus::exception::exception& e)
Matt Spinler34af47f2018-07-16 14:07:03 -050072 {
73 log<level::ERR>("sdbusplus error getting logging managed objects",
74 entry("ERROR=%s", e.what()));
75 }
Matt Spinler54bfa7e2018-03-27 11:28:59 -050076}
77
Matt Spinlere6a51592018-05-23 12:47:10 -050078void Manager::createWithRestore(const std::string& objectPath,
79 const DbusInterfaceMap& interfaces)
Matt Spinler54bfa7e2018-03-27 11:28:59 -050080{
Matt Spinlere6a51592018-05-23 12:47:10 -050081 createObject(objectPath, interfaces);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050082
Matt Spinler60f53d82018-05-23 13:23:09 -050083 restoreCalloutObjects(objectPath, interfaces);
Matt Spinlere6a51592018-05-23 12:47:10 -050084}
85
86void Manager::create(const std::string& objectPath,
87 const DbusInterfaceMap& interfaces)
88{
89 createObject(objectPath, interfaces);
90
Matt Spinler52ee71b2018-05-23 13:18:55 -050091 createCalloutObjects(objectPath, interfaces);
Matt Spinlere6a51592018-05-23 12:47:10 -050092}
93
94void Manager::createObject(const std::string& objectPath,
95 const DbusInterfaceMap& interfaces)
96{
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050097#ifdef USE_POLICY_INTERFACE
Matt Spinlere6a51592018-05-23 12:47:10 -050098 auto logInterface = interfaces.find(LOGGING_IFACE);
99 createPolicyInterface(objectPath, logInterface->second);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500100#endif
Matt Spinlere0017eb2018-03-27 11:17:38 -0500101}
102
Matt Spinlera1390352018-05-23 10:48:19 -0500103void Manager::erase(EntryID id)
104{
Matt Spinler52ee71b2018-05-23 13:18:55 -0500105 fs::remove_all(getSaveDir(id));
Matt Spinler677143b2018-05-23 10:53:27 -0500106 childEntries.erase(id);
Matt Spinlera1390352018-05-23 10:48:19 -0500107 entries.erase(id);
108}
109
Matt Spinler491fc6f2018-04-23 11:00:52 -0500110void Manager::addInterface(const std::string& objectPath, InterfaceType type,
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500111 std::any& object)
Matt Spinler491fc6f2018-04-23 11:00:52 -0500112{
113 auto id = getEntryID(objectPath);
114 auto entry = entries.find(id);
115
116 if (entry == entries.end())
117 {
118 InterfaceMap interfaces;
119 interfaces.emplace(type, object);
120 entries.emplace(id, std::move(interfaces));
121 }
122 else
123 {
124 entry->second.emplace(type, object);
125 }
126}
127
Matt Spinler677143b2018-05-23 10:53:27 -0500128void Manager::addChildInterface(const std::string& objectPath,
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500129 InterfaceType type, std::any& object)
Matt Spinler677143b2018-05-23 10:53:27 -0500130{
131 auto id = getEntryID(objectPath);
132 auto entry = childEntries.find(id);
133
134 // childEntries is:
135 // A map of error log entry IDs to:
136 // a map of interface types to:
137 // a vector of interface objects
138
139 if (entry == childEntries.end())
140 {
141 ObjectList objects{object};
142 InterfaceMapMulti interfaces;
143 interfaces.emplace(type, std::move(objects));
144 childEntries.emplace(id, std::move(interfaces));
145 }
146 else
147 {
148 auto i = entry->second.find(type);
149 if (i == entry->second.end())
150 {
151 ObjectList objects{objects};
152 entry->second.emplace(type, objects);
153 }
154 else
155 {
156 i->second.emplace_back(object);
157 }
158 }
159}
160
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500161#ifdef USE_POLICY_INTERFACE
Matt Spinler259e7272018-03-29 10:57:17 -0500162void Manager::createPolicyInterface(const std::string& objectPath,
163 const DbusPropertyMap& properties)
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500164{
165 auto values = policy::find(policies, properties);
166
Matt Spinler259e7272018-03-29 10:57:17 -0500167 auto object = std::make_shared<PolicyObject>(bus, objectPath.c_str(), true);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500168
169 object->eventID(std::get<policy::EIDField>(values));
170 object->description(std::get<policy::MsgField>(values));
171
Matt Spinler9bea4ea2018-05-09 15:53:04 -0500172 object->emit_object_added();
173
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500174 std::any anyObject = object;
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500175
Matt Spinler491fc6f2018-04-23 11:00:52 -0500176 addInterface(objectPath, InterfaceType::POLICY, anyObject);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500177}
178#endif
179
Matt Spinler52ee71b2018-05-23 13:18:55 -0500180void Manager::createCalloutObjects(const std::string& objectPath,
181 const DbusInterfaceMap& interfaces)
182{
183 // Use the associations property in the org.openbmc.Associations
184 // interface to find any callouts. Then grab all properties on
185 // the Asset interface for that object in the inventory to use
186 // in our callout objects.
187
188 auto associations = interfaces.find(ASSOC_IFACE);
189 if (associations == interfaces.end())
190 {
191 return;
192 }
193
194 const auto& properties = associations->second;
Matt Spinler4c0e8942019-11-06 11:29:45 -0600195 auto assocProperty = properties.find("Associations");
Patrick Williamsb5af3a32020-05-13 11:11:32 -0500196 auto assocValue = std::get<AssociationsPropertyType>(assocProperty->second);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500197
198 auto id = getEntryID(objectPath);
199 auto calloutNum = 0;
200 DbusSubtree subtree;
201
202 for (const auto& association : assocValue)
203 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500204 try
Matt Spinler52ee71b2018-05-23 13:18:55 -0500205 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500206 if (std::get<forwardPos>(association) != "callout")
207 {
208 continue;
209 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500210
Matt Spinler34af47f2018-07-16 14:07:03 -0500211 auto callout = std::get<endpointPos>(association);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500212
Matt Spinler52ee71b2018-05-23 13:18:55 -0500213 if (subtree.empty())
214 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500215 subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
216 if (subtree.empty())
217 {
218 break;
219 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500220 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500221
Matt Spinler34af47f2018-07-16 14:07:03 -0500222 auto service = getService(callout, ASSET_IFACE, subtree);
223 if (service.empty())
224 {
225 continue;
226 }
227
228 auto properties =
229 getAllProperties(bus, service, callout, ASSET_IFACE);
230 if (properties.empty())
231 {
232 continue;
233 }
234
235 auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
236
237 auto object = std::make_shared<Callout>(
238 bus, calloutPath, callout, calloutNum,
239 getLogTimestamp(interfaces), properties);
240
241 auto dir = getCalloutSaveDir(id);
242 if (!fs::exists(dir))
243 {
244 fs::create_directories(dir);
245 }
246 object->serialize(dir);
247
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500248 std::any anyObject = object;
Matt Spinler34af47f2018-07-16 14:07:03 -0500249 addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
250 calloutNum++;
251 }
Matt Spinler1eb63672021-09-02 16:41:27 -0500252 catch (const sdbusplus::exception::exception& e)
Matt Spinler52ee71b2018-05-23 13:18:55 -0500253 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500254 log<level::ERR>("sdbusplus exception", entry("ERROR=%s", e.what()));
Matt Spinler52ee71b2018-05-23 13:18:55 -0500255 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500256 }
257}
258
Matt Spinler60f53d82018-05-23 13:23:09 -0500259void Manager::restoreCalloutObjects(const std::string& objectPath,
260 const DbusInterfaceMap& interfaces)
261{
262 auto saveDir = getCalloutSaveDir(getEntryID(objectPath));
263
264 if (!fs::exists(saveDir))
265 {
266 return;
267 }
268
269 size_t id;
270 for (auto& f : fs::directory_iterator(saveDir))
271 {
272 try
273 {
274 id = std::stoul(f.path().filename());
275 }
Patrick Williamsbf9ea8a2021-10-06 13:10:21 -0500276 catch (const std::exception& e)
Matt Spinler60f53d82018-05-23 13:23:09 -0500277 {
Matt Spinler60f53d82018-05-23 13:23:09 -0500278 log<level::ERR>("Invalid IBM logging callout save file. Deleting",
279 entry("FILE=%s", f.path().c_str()));
280 fs::remove(f.path());
281 continue;
282 }
283
284 auto path = getCalloutObjectPath(objectPath, id);
285 auto callout = std::make_shared<Callout>(bus, path, id,
286 getLogTimestamp(interfaces));
287 if (callout->deserialize(saveDir))
288 {
289 callout->emit_object_added();
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500290 std::any anyObject = callout;
Matt Spinler60f53d82018-05-23 13:23:09 -0500291 addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
292 }
293 }
294}
295
Matt Spinlere0017eb2018-03-27 11:17:38 -0500296void Manager::interfaceAdded(sdbusplus::message::message& msg)
297{
298 sdbusplus::message::object_path path;
299 DbusInterfaceMap interfaces;
300
301 msg.read(path, interfaces);
302
Matt Spinler259e7272018-03-29 10:57:17 -0500303 // Find the Logging.Entry interface with all of its properties
304 // to pass to create().
Matt Spinlere6a51592018-05-23 12:47:10 -0500305 if (interfaces.find(LOGGING_IFACE) != interfaces.end())
Matt Spinlere0017eb2018-03-27 11:17:38 -0500306 {
Matt Spinlere6a51592018-05-23 12:47:10 -0500307 create(path, interfaces);
Matt Spinlere0017eb2018-03-27 11:17:38 -0500308 }
309}
Matt Spinler055da3b2018-05-09 15:51:20 -0500310
Matt Spinler52ee71b2018-05-23 13:18:55 -0500311uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
312{
313 auto interface = interfaces.find(LOGGING_IFACE);
314 if (interface != interfaces.end())
315 {
316 auto property = interface->second.find("Timestamp");
317 if (property != interface->second.end())
318 {
Patrick Williamsb5af3a32020-05-13 11:11:32 -0500319 return std::get<uint64_t>(property->second);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500320 }
321 }
322
323 return 0;
324}
325
326fs::path Manager::getSaveDir(EntryID id)
327{
328 return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
329}
330
331fs::path Manager::getCalloutSaveDir(EntryID id)
332{
333 return getSaveDir(id) / "callouts";
334}
335
336std::string Manager::getCalloutObjectPath(const std::string& objectPath,
337 uint32_t calloutNum)
338{
339 return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
340}
341
Matt Spinler055da3b2018-05-09 15:51:20 -0500342void Manager::interfaceRemoved(sdbusplus::message::message& msg)
343{
344 sdbusplus::message::object_path path;
345 DbusInterfaceList interfaces;
346
347 msg.read(path, interfaces);
348
349 // If the Logging.Entry interface was removed, then remove
350 // our object
351
352 auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE);
353
354 if (i != interfaces.end())
355 {
Matt Spinlera1390352018-05-23 10:48:19 -0500356 erase(getEntryID(path));
Matt Spinler055da3b2018-05-09 15:51:20 -0500357 }
358}
Matt Spinler66e07072018-09-12 10:36:14 -0500359} // namespace logging
360} // namespace ibm