blob: 2342743c4216cc8aa12b14e7a20ea930b3617b4d [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;
32using sdbusplus::exception::SdBusError;
Matt Spinler52ee71b2018-05-23 13:18:55 -050033
Matt Spinlere0017eb2018-03-27 11:17:38 -050034Manager::Manager(sdbusplus::bus::bus& bus) :
Matt Spinler259e7272018-03-29 10:57:17 -050035 bus(bus),
36 addMatch(bus,
37 sdbusplus::bus::match::rules::interfacesAdded() +
38 sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
39 std::bind(std::mem_fn(&Manager::interfaceAdded), this,
Matt Spinler055da3b2018-05-09 15:51:20 -050040 std::placeholders::_1)),
41 removeMatch(bus,
42 sdbusplus::bus::match::rules::interfacesRemoved() +
43 sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
44 std::bind(std::mem_fn(&Manager::interfaceRemoved), this,
45 std::placeholders::_1))
Matt Spinler743e5822018-03-27 13:44:50 -050046#ifdef USE_POLICY_INTERFACE
Matt Spinler259e7272018-03-29 10:57:17 -050047 ,
48 policies(POLICY_JSON_PATH)
Matt Spinler743e5822018-03-27 13:44:50 -050049#endif
Matt Spinlere0017eb2018-03-27 11:17:38 -050050{
Matt Spinler54bfa7e2018-03-27 11:28:59 -050051 createAll();
52}
53
54void Manager::createAll()
55{
Matt Spinler34af47f2018-07-16 14:07:03 -050056 try
Matt Spinler54bfa7e2018-03-27 11:28:59 -050057 {
Matt Spinler34af47f2018-07-16 14:07:03 -050058 auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH);
Matt Spinler54bfa7e2018-03-27 11:28:59 -050059
Matt Spinler34af47f2018-07-16 14:07:03 -050060 for (const auto& object : objects)
Matt Spinler54bfa7e2018-03-27 11:28:59 -050061 {
Matt Spinler34af47f2018-07-16 14:07:03 -050062 const auto& interfaces = object.second;
63
64 auto propertyMap = interfaces.find(LOGGING_IFACE);
65
66 if (propertyMap != interfaces.end())
67 {
68 createWithRestore(object.first, interfaces);
69 }
Matt Spinler54bfa7e2018-03-27 11:28:59 -050070 }
71 }
Matt Spinler34af47f2018-07-16 14:07:03 -050072 catch (const SdBusError& e)
73 {
74 log<level::ERR>("sdbusplus error getting logging managed objects",
75 entry("ERROR=%s", e.what()));
76 }
Matt Spinler54bfa7e2018-03-27 11:28:59 -050077}
78
Matt Spinlere6a51592018-05-23 12:47:10 -050079void Manager::createWithRestore(const std::string& objectPath,
80 const DbusInterfaceMap& interfaces)
Matt Spinler54bfa7e2018-03-27 11:28:59 -050081{
Matt Spinlere6a51592018-05-23 12:47:10 -050082 createObject(objectPath, interfaces);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050083
Matt Spinler60f53d82018-05-23 13:23:09 -050084 restoreCalloutObjects(objectPath, interfaces);
Matt Spinlere6a51592018-05-23 12:47:10 -050085}
86
87void Manager::create(const std::string& objectPath,
88 const DbusInterfaceMap& interfaces)
89{
90 createObject(objectPath, interfaces);
91
Matt Spinler52ee71b2018-05-23 13:18:55 -050092 createCalloutObjects(objectPath, interfaces);
Matt Spinlere6a51592018-05-23 12:47:10 -050093}
94
95void Manager::createObject(const std::string& objectPath,
96 const DbusInterfaceMap& interfaces)
97{
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050098#ifdef USE_POLICY_INTERFACE
Matt Spinlere6a51592018-05-23 12:47:10 -050099 auto logInterface = interfaces.find(LOGGING_IFACE);
100 createPolicyInterface(objectPath, logInterface->second);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500101#endif
Matt Spinlere0017eb2018-03-27 11:17:38 -0500102}
103
Matt Spinlera1390352018-05-23 10:48:19 -0500104void Manager::erase(EntryID id)
105{
Matt Spinler52ee71b2018-05-23 13:18:55 -0500106 fs::remove_all(getSaveDir(id));
Matt Spinler677143b2018-05-23 10:53:27 -0500107 childEntries.erase(id);
Matt Spinlera1390352018-05-23 10:48:19 -0500108 entries.erase(id);
109}
110
Matt Spinler491fc6f2018-04-23 11:00:52 -0500111void Manager::addInterface(const std::string& objectPath, InterfaceType type,
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500112 std::any& object)
Matt Spinler491fc6f2018-04-23 11:00:52 -0500113{
114 auto id = getEntryID(objectPath);
115 auto entry = entries.find(id);
116
117 if (entry == entries.end())
118 {
119 InterfaceMap interfaces;
120 interfaces.emplace(type, object);
121 entries.emplace(id, std::move(interfaces));
122 }
123 else
124 {
125 entry->second.emplace(type, object);
126 }
127}
128
Matt Spinler677143b2018-05-23 10:53:27 -0500129void Manager::addChildInterface(const std::string& objectPath,
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500130 InterfaceType type, std::any& object)
Matt Spinler677143b2018-05-23 10:53:27 -0500131{
132 auto id = getEntryID(objectPath);
133 auto entry = childEntries.find(id);
134
135 // childEntries is:
136 // A map of error log entry IDs to:
137 // a map of interface types to:
138 // a vector of interface objects
139
140 if (entry == childEntries.end())
141 {
142 ObjectList objects{object};
143 InterfaceMapMulti interfaces;
144 interfaces.emplace(type, std::move(objects));
145 childEntries.emplace(id, std::move(interfaces));
146 }
147 else
148 {
149 auto i = entry->second.find(type);
150 if (i == entry->second.end())
151 {
152 ObjectList objects{objects};
153 entry->second.emplace(type, objects);
154 }
155 else
156 {
157 i->second.emplace_back(object);
158 }
159 }
160}
161
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500162#ifdef USE_POLICY_INTERFACE
Matt Spinler259e7272018-03-29 10:57:17 -0500163void Manager::createPolicyInterface(const std::string& objectPath,
164 const DbusPropertyMap& properties)
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500165{
166 auto values = policy::find(policies, properties);
167
Matt Spinler259e7272018-03-29 10:57:17 -0500168 auto object = std::make_shared<PolicyObject>(bus, objectPath.c_str(), true);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500169
170 object->eventID(std::get<policy::EIDField>(values));
171 object->description(std::get<policy::MsgField>(values));
172
Matt Spinler9bea4ea2018-05-09 15:53:04 -0500173 object->emit_object_added();
174
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500175 std::any anyObject = object;
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500176
Matt Spinler491fc6f2018-04-23 11:00:52 -0500177 addInterface(objectPath, InterfaceType::POLICY, anyObject);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500178}
179#endif
180
Matt Spinler52ee71b2018-05-23 13:18:55 -0500181void Manager::createCalloutObjects(const std::string& objectPath,
182 const DbusInterfaceMap& interfaces)
183{
184 // Use the associations property in the org.openbmc.Associations
185 // interface to find any callouts. Then grab all properties on
186 // the Asset interface for that object in the inventory to use
187 // in our callout objects.
188
189 auto associations = interfaces.find(ASSOC_IFACE);
190 if (associations == interfaces.end())
191 {
192 return;
193 }
194
195 const auto& properties = associations->second;
196 auto assocProperty = properties.find("associations");
William A. Kennington IIIf5866e72018-11-12 15:46:11 -0800197 auto assocValue =
198 sdbusplus::message::variant_ns::get<AssociationsPropertyType>(
199 assocProperty->second);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500200
201 auto id = getEntryID(objectPath);
202 auto calloutNum = 0;
203 DbusSubtree subtree;
204
205 for (const auto& association : assocValue)
206 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500207 try
Matt Spinler52ee71b2018-05-23 13:18:55 -0500208 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500209 if (std::get<forwardPos>(association) != "callout")
210 {
211 continue;
212 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500213
Matt Spinler34af47f2018-07-16 14:07:03 -0500214 auto callout = std::get<endpointPos>(association);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500215
Matt Spinler52ee71b2018-05-23 13:18:55 -0500216 if (subtree.empty())
217 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500218 subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
219 if (subtree.empty())
220 {
221 break;
222 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500223 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500224
Matt Spinler34af47f2018-07-16 14:07:03 -0500225 auto service = getService(callout, ASSET_IFACE, subtree);
226 if (service.empty())
227 {
228 continue;
229 }
230
231 auto properties =
232 getAllProperties(bus, service, callout, ASSET_IFACE);
233 if (properties.empty())
234 {
235 continue;
236 }
237
238 auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
239
240 auto object = std::make_shared<Callout>(
241 bus, calloutPath, callout, calloutNum,
242 getLogTimestamp(interfaces), properties);
243
244 auto dir = getCalloutSaveDir(id);
245 if (!fs::exists(dir))
246 {
247 fs::create_directories(dir);
248 }
249 object->serialize(dir);
250
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500251 std::any anyObject = object;
Matt Spinler34af47f2018-07-16 14:07:03 -0500252 addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
253 calloutNum++;
254 }
255 catch (const SdBusError& e)
Matt Spinler52ee71b2018-05-23 13:18:55 -0500256 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500257 log<level::ERR>("sdbusplus exception", entry("ERROR=%s", e.what()));
Matt Spinler52ee71b2018-05-23 13:18:55 -0500258 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500259 }
260}
261
Matt Spinler60f53d82018-05-23 13:23:09 -0500262void Manager::restoreCalloutObjects(const std::string& objectPath,
263 const DbusInterfaceMap& interfaces)
264{
265 auto saveDir = getCalloutSaveDir(getEntryID(objectPath));
266
267 if (!fs::exists(saveDir))
268 {
269 return;
270 }
271
272 size_t id;
273 for (auto& f : fs::directory_iterator(saveDir))
274 {
275 try
276 {
277 id = std::stoul(f.path().filename());
278 }
279 catch (std::exception& e)
280 {
Matt Spinler60f53d82018-05-23 13:23:09 -0500281 log<level::ERR>("Invalid IBM logging callout save file. Deleting",
282 entry("FILE=%s", f.path().c_str()));
283 fs::remove(f.path());
284 continue;
285 }
286
287 auto path = getCalloutObjectPath(objectPath, id);
288 auto callout = std::make_shared<Callout>(bus, path, id,
289 getLogTimestamp(interfaces));
290 if (callout->deserialize(saveDir))
291 {
292 callout->emit_object_added();
Matt Spinler54ea3ad2018-10-23 10:40:09 -0500293 std::any anyObject = callout;
Matt Spinler60f53d82018-05-23 13:23:09 -0500294 addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
295 }
296 }
297}
298
Matt Spinlere0017eb2018-03-27 11:17:38 -0500299void Manager::interfaceAdded(sdbusplus::message::message& msg)
300{
301 sdbusplus::message::object_path path;
302 DbusInterfaceMap interfaces;
303
304 msg.read(path, interfaces);
305
Matt Spinler259e7272018-03-29 10:57:17 -0500306 // Find the Logging.Entry interface with all of its properties
307 // to pass to create().
Matt Spinlere6a51592018-05-23 12:47:10 -0500308 if (interfaces.find(LOGGING_IFACE) != interfaces.end())
Matt Spinlere0017eb2018-03-27 11:17:38 -0500309 {
Matt Spinlere6a51592018-05-23 12:47:10 -0500310 create(path, interfaces);
Matt Spinlere0017eb2018-03-27 11:17:38 -0500311 }
312}
Matt Spinler055da3b2018-05-09 15:51:20 -0500313
Matt Spinler52ee71b2018-05-23 13:18:55 -0500314uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
315{
316 auto interface = interfaces.find(LOGGING_IFACE);
317 if (interface != interfaces.end())
318 {
319 auto property = interface->second.find("Timestamp");
320 if (property != interface->second.end())
321 {
William A. Kennington IIIf5866e72018-11-12 15:46:11 -0800322 return sdbusplus::message::variant_ns::get<uint64_t>(
323 property->second);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500324 }
325 }
326
327 return 0;
328}
329
330fs::path Manager::getSaveDir(EntryID id)
331{
332 return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
333}
334
335fs::path Manager::getCalloutSaveDir(EntryID id)
336{
337 return getSaveDir(id) / "callouts";
338}
339
340std::string Manager::getCalloutObjectPath(const std::string& objectPath,
341 uint32_t calloutNum)
342{
343 return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
344}
345
Matt Spinler055da3b2018-05-09 15:51:20 -0500346void Manager::interfaceRemoved(sdbusplus::message::message& msg)
347{
348 sdbusplus::message::object_path path;
349 DbusInterfaceList interfaces;
350
351 msg.read(path, interfaces);
352
353 // If the Logging.Entry interface was removed, then remove
354 // our object
355
356 auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE);
357
358 if (i != interfaces.end())
359 {
Matt Spinlera1390352018-05-23 10:48:19 -0500360 erase(getEntryID(path));
Matt Spinler055da3b2018-05-09 15:51:20 -0500361 }
362}
Matt Spinler66e07072018-09-12 10:36:14 -0500363} // namespace logging
364} // namespace ibm