blob: 7c53a08681d33383bf1ed3c06af978d896ed9b76 [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 */
Matt Spinler60f53d82018-05-23 13:23:09 -050016#include <phosphor-logging/log.hpp>
Matt Spinler52ee71b2018-05-23 13:18:55 -050017#include "callout.hpp"
Matt Spinlere0017eb2018-03-27 11:17:38 -050018#include "config.h"
19#include "manager.hpp"
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050020#include "policy_find.hpp"
Matt Spinlere0017eb2018-03-27 11:17:38 -050021
22namespace ibm
23{
24namespace logging
25{
26
Matt Spinler52ee71b2018-05-23 13:18:55 -050027namespace fs = std::experimental::filesystem;
Matt Spinler34af47f2018-07-16 14:07:03 -050028using namespace phosphor::logging;
29using sdbusplus::exception::SdBusError;
Matt Spinler52ee71b2018-05-23 13:18:55 -050030
Matt Spinlere0017eb2018-03-27 11:17:38 -050031Manager::Manager(sdbusplus::bus::bus& bus) :
Matt Spinler259e7272018-03-29 10:57:17 -050032 bus(bus),
33 addMatch(bus,
34 sdbusplus::bus::match::rules::interfacesAdded() +
35 sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
36 std::bind(std::mem_fn(&Manager::interfaceAdded), this,
Matt Spinler055da3b2018-05-09 15:51:20 -050037 std::placeholders::_1)),
38 removeMatch(bus,
39 sdbusplus::bus::match::rules::interfacesRemoved() +
40 sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
41 std::bind(std::mem_fn(&Manager::interfaceRemoved), this,
42 std::placeholders::_1))
Matt Spinler743e5822018-03-27 13:44:50 -050043#ifdef USE_POLICY_INTERFACE
Matt Spinler259e7272018-03-29 10:57:17 -050044 ,
45 policies(POLICY_JSON_PATH)
Matt Spinler743e5822018-03-27 13:44:50 -050046#endif
Matt Spinlere0017eb2018-03-27 11:17:38 -050047{
Matt Spinler54bfa7e2018-03-27 11:28:59 -050048 createAll();
49}
50
51void Manager::createAll()
52{
Matt Spinler34af47f2018-07-16 14:07:03 -050053 try
Matt Spinler54bfa7e2018-03-27 11:28:59 -050054 {
Matt Spinler34af47f2018-07-16 14:07:03 -050055 auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH);
Matt Spinler54bfa7e2018-03-27 11:28:59 -050056
Matt Spinler34af47f2018-07-16 14:07:03 -050057 for (const auto& object : objects)
Matt Spinler54bfa7e2018-03-27 11:28:59 -050058 {
Matt Spinler34af47f2018-07-16 14:07:03 -050059 const auto& interfaces = object.second;
60
61 auto propertyMap = interfaces.find(LOGGING_IFACE);
62
63 if (propertyMap != interfaces.end())
64 {
65 createWithRestore(object.first, interfaces);
66 }
Matt Spinler54bfa7e2018-03-27 11:28:59 -050067 }
68 }
Matt Spinler34af47f2018-07-16 14:07:03 -050069 catch (const SdBusError& e)
70 {
71 log<level::ERR>("sdbusplus error getting logging managed objects",
72 entry("ERROR=%s", e.what()));
73 }
Matt Spinler54bfa7e2018-03-27 11:28:59 -050074}
75
Matt Spinlere6a51592018-05-23 12:47:10 -050076void Manager::createWithRestore(const std::string& objectPath,
77 const DbusInterfaceMap& interfaces)
Matt Spinler54bfa7e2018-03-27 11:28:59 -050078{
Matt Spinlere6a51592018-05-23 12:47:10 -050079 createObject(objectPath, interfaces);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050080
Matt Spinler60f53d82018-05-23 13:23:09 -050081 restoreCalloutObjects(objectPath, interfaces);
Matt Spinlere6a51592018-05-23 12:47:10 -050082}
83
84void Manager::create(const std::string& objectPath,
85 const DbusInterfaceMap& interfaces)
86{
87 createObject(objectPath, interfaces);
88
Matt Spinler52ee71b2018-05-23 13:18:55 -050089 createCalloutObjects(objectPath, interfaces);
Matt Spinlere6a51592018-05-23 12:47:10 -050090}
91
92void Manager::createObject(const std::string& objectPath,
93 const DbusInterfaceMap& interfaces)
94{
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050095#ifdef USE_POLICY_INTERFACE
Matt Spinlere6a51592018-05-23 12:47:10 -050096 auto logInterface = interfaces.find(LOGGING_IFACE);
97 createPolicyInterface(objectPath, logInterface->second);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050098#endif
Matt Spinlere0017eb2018-03-27 11:17:38 -050099}
100
Matt Spinlera1390352018-05-23 10:48:19 -0500101void Manager::erase(EntryID id)
102{
Matt Spinler52ee71b2018-05-23 13:18:55 -0500103 fs::remove_all(getSaveDir(id));
Matt Spinler677143b2018-05-23 10:53:27 -0500104 childEntries.erase(id);
Matt Spinlera1390352018-05-23 10:48:19 -0500105 entries.erase(id);
106}
107
Matt Spinler491fc6f2018-04-23 11:00:52 -0500108void Manager::addInterface(const std::string& objectPath, InterfaceType type,
109 std::experimental::any& object)
110{
111 auto id = getEntryID(objectPath);
112 auto entry = entries.find(id);
113
114 if (entry == entries.end())
115 {
116 InterfaceMap interfaces;
117 interfaces.emplace(type, object);
118 entries.emplace(id, std::move(interfaces));
119 }
120 else
121 {
122 entry->second.emplace(type, object);
123 }
124}
125
Matt Spinler677143b2018-05-23 10:53:27 -0500126void Manager::addChildInterface(const std::string& objectPath,
127 InterfaceType type,
128 std::experimental::any& object)
129{
130 auto id = getEntryID(objectPath);
131 auto entry = childEntries.find(id);
132
133 // childEntries is:
134 // A map of error log entry IDs to:
135 // a map of interface types to:
136 // a vector of interface objects
137
138 if (entry == childEntries.end())
139 {
140 ObjectList objects{object};
141 InterfaceMapMulti interfaces;
142 interfaces.emplace(type, std::move(objects));
143 childEntries.emplace(id, std::move(interfaces));
144 }
145 else
146 {
147 auto i = entry->second.find(type);
148 if (i == entry->second.end())
149 {
150 ObjectList objects{objects};
151 entry->second.emplace(type, objects);
152 }
153 else
154 {
155 i->second.emplace_back(object);
156 }
157 }
158}
159
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500160#ifdef USE_POLICY_INTERFACE
Matt Spinler259e7272018-03-29 10:57:17 -0500161void Manager::createPolicyInterface(const std::string& objectPath,
162 const DbusPropertyMap& properties)
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500163{
164 auto values = policy::find(policies, properties);
165
Matt Spinler259e7272018-03-29 10:57:17 -0500166 auto object = std::make_shared<PolicyObject>(bus, objectPath.c_str(), true);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500167
168 object->eventID(std::get<policy::EIDField>(values));
169 object->description(std::get<policy::MsgField>(values));
170
Matt Spinler9bea4ea2018-05-09 15:53:04 -0500171 object->emit_object_added();
172
Matt Spinler491fc6f2018-04-23 11:00:52 -0500173 std::experimental::any anyObject = object;
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500174
Matt Spinler491fc6f2018-04-23 11:00:52 -0500175 addInterface(objectPath, InterfaceType::POLICY, anyObject);
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500176}
177#endif
178
Matt Spinler52ee71b2018-05-23 13:18:55 -0500179void Manager::createCalloutObjects(const std::string& objectPath,
180 const DbusInterfaceMap& interfaces)
181{
182 // Use the associations property in the org.openbmc.Associations
183 // interface to find any callouts. Then grab all properties on
184 // the Asset interface for that object in the inventory to use
185 // in our callout objects.
186
187 auto associations = interfaces.find(ASSOC_IFACE);
188 if (associations == interfaces.end())
189 {
190 return;
191 }
192
193 const auto& properties = associations->second;
194 auto assocProperty = properties.find("associations");
195 auto assocValue = assocProperty->second.get<AssociationsPropertyType>();
196
197 auto id = getEntryID(objectPath);
198 auto calloutNum = 0;
199 DbusSubtree subtree;
200
201 for (const auto& association : assocValue)
202 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500203 try
Matt Spinler52ee71b2018-05-23 13:18:55 -0500204 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500205 if (std::get<forwardPos>(association) != "callout")
206 {
207 continue;
208 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500209
Matt Spinler34af47f2018-07-16 14:07:03 -0500210 auto callout = std::get<endpointPos>(association);
Matt Spinler52ee71b2018-05-23 13:18:55 -0500211
Matt Spinler52ee71b2018-05-23 13:18:55 -0500212 if (subtree.empty())
213 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500214 subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
215 if (subtree.empty())
216 {
217 break;
218 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500219 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500220
Matt Spinler34af47f2018-07-16 14:07:03 -0500221 auto service = getService(callout, ASSET_IFACE, subtree);
222 if (service.empty())
223 {
224 continue;
225 }
226
227 auto properties =
228 getAllProperties(bus, service, callout, ASSET_IFACE);
229 if (properties.empty())
230 {
231 continue;
232 }
233
234 auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
235
236 auto object = std::make_shared<Callout>(
237 bus, calloutPath, callout, calloutNum,
238 getLogTimestamp(interfaces), properties);
239
240 auto dir = getCalloutSaveDir(id);
241 if (!fs::exists(dir))
242 {
243 fs::create_directories(dir);
244 }
245 object->serialize(dir);
246
247 std::experimental::any anyObject = object;
248 addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
249 calloutNum++;
250 }
251 catch (const SdBusError& e)
Matt Spinler52ee71b2018-05-23 13:18:55 -0500252 {
Matt Spinler34af47f2018-07-16 14:07:03 -0500253 log<level::ERR>("sdbusplus exception", entry("ERROR=%s", e.what()));
Matt Spinler52ee71b2018-05-23 13:18:55 -0500254 }
Matt Spinler52ee71b2018-05-23 13:18:55 -0500255 }
256}
257
Matt Spinler60f53d82018-05-23 13:23:09 -0500258void Manager::restoreCalloutObjects(const std::string& objectPath,
259 const DbusInterfaceMap& interfaces)
260{
261 auto saveDir = getCalloutSaveDir(getEntryID(objectPath));
262
263 if (!fs::exists(saveDir))
264 {
265 return;
266 }
267
268 size_t id;
269 for (auto& f : fs::directory_iterator(saveDir))
270 {
271 try
272 {
273 id = std::stoul(f.path().filename());
274 }
275 catch (std::exception& e)
276 {
Matt Spinler60f53d82018-05-23 13:23:09 -0500277 log<level::ERR>("Invalid IBM logging callout save file. Deleting",
278 entry("FILE=%s", f.path().c_str()));
279 fs::remove(f.path());
280 continue;
281 }
282
283 auto path = getCalloutObjectPath(objectPath, id);
284 auto callout = std::make_shared<Callout>(bus, path, id,
285 getLogTimestamp(interfaces));
286 if (callout->deserialize(saveDir))
287 {
288 callout->emit_object_added();
289 std::experimental::any anyObject = callout;
290 addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
291 }
292 }
293}
294
Matt Spinlere0017eb2018-03-27 11:17:38 -0500295void Manager::interfaceAdded(sdbusplus::message::message& msg)
296{
297 sdbusplus::message::object_path path;
298 DbusInterfaceMap interfaces;
299
300 msg.read(path, interfaces);
301
Matt Spinler259e7272018-03-29 10:57:17 -0500302 // Find the Logging.Entry interface with all of its properties
303 // to pass to create().
Matt Spinlere6a51592018-05-23 12:47:10 -0500304 if (interfaces.find(LOGGING_IFACE) != interfaces.end())
Matt Spinlere0017eb2018-03-27 11:17:38 -0500305 {
Matt Spinlere6a51592018-05-23 12:47:10 -0500306 create(path, interfaces);
Matt Spinlere0017eb2018-03-27 11:17:38 -0500307 }
308}
Matt Spinler055da3b2018-05-09 15:51:20 -0500309
Matt Spinler52ee71b2018-05-23 13:18:55 -0500310uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
311{
312 auto interface = interfaces.find(LOGGING_IFACE);
313 if (interface != interfaces.end())
314 {
315 auto property = interface->second.find("Timestamp");
316 if (property != interface->second.end())
317 {
318 return property->second.get<uint64_t>();
319 }
320 }
321
322 return 0;
323}
324
325fs::path Manager::getSaveDir(EntryID id)
326{
327 return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
328}
329
330fs::path Manager::getCalloutSaveDir(EntryID id)
331{
332 return getSaveDir(id) / "callouts";
333}
334
335std::string Manager::getCalloutObjectPath(const std::string& objectPath,
336 uint32_t calloutNum)
337{
338 return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
339}
340
Matt Spinler055da3b2018-05-09 15:51:20 -0500341void Manager::interfaceRemoved(sdbusplus::message::message& msg)
342{
343 sdbusplus::message::object_path path;
344 DbusInterfaceList interfaces;
345
346 msg.read(path, interfaces);
347
348 // If the Logging.Entry interface was removed, then remove
349 // our object
350
351 auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE);
352
353 if (i != interfaces.end())
354 {
Matt Spinlera1390352018-05-23 10:48:19 -0500355 erase(getEntryID(path));
Matt Spinler055da3b2018-05-09 15:51:20 -0500356 }
357}
Matt Spinlere0017eb2018-03-27 11:17:38 -0500358}
359}