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 */
16e0017ebbSMatt Spinler #include "config.h"
1766e07073SMatt Spinler
18e0017ebbSMatt Spinler #include "manager.hpp"
1966e07073SMatt Spinler
2066e07073SMatt Spinler #include "callout.hpp"
214a6ea6afSMatt Spinler #include "policy_find.hpp"
22e0017ebbSMatt Spinler
2366e07073SMatt Spinler #include <phosphor-logging/log.hpp>
2466e07073SMatt Spinler
25e0017ebbSMatt Spinler namespace ibm
26e0017ebbSMatt Spinler {
27e0017ebbSMatt Spinler namespace logging
28e0017ebbSMatt Spinler {
29e0017ebbSMatt Spinler
3052ee71bdSMatt Spinler namespace fs = std::experimental::filesystem;
3134af47ffSMatt Spinler using namespace phosphor::logging;
3252ee71bdSMatt Spinler
Manager(sdbusplus::bus_t & bus)338123a713SPatrick Williams Manager::Manager(sdbusplus::bus_t& bus) :
34e0017ebbSMatt Spinler bus(bus),
35259e7277SMatt Spinler addMatch(bus,
36e0017ebbSMatt Spinler sdbusplus::bus::match::rules::interfacesAdded() +
37e0017ebbSMatt Spinler sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
38259e7277SMatt Spinler std::bind(std::mem_fn(&Manager::interfaceAdded), this,
39055da3bdSMatt Spinler std::placeholders::_1)),
40055da3bdSMatt Spinler removeMatch(bus,
41055da3bdSMatt Spinler sdbusplus::bus::match::rules::interfacesRemoved() +
42055da3bdSMatt Spinler sdbusplus::bus::match::rules::path_namespace(LOGGING_PATH),
43055da3bdSMatt Spinler std::bind(std::mem_fn(&Manager::interfaceRemoved), this,
44259e7277SMatt Spinler std::placeholders::_1))
45743e5822SMatt Spinler #ifdef USE_POLICY_INTERFACE
46259e7277SMatt Spinler ,
47259e7277SMatt Spinler policies(POLICY_JSON_PATH)
48743e5822SMatt Spinler #endif
49e0017ebbSMatt Spinler {
5054bfa7e7SMatt Spinler createAll();
5154bfa7e7SMatt Spinler }
5254bfa7e7SMatt Spinler
createAll()5354bfa7e7SMatt Spinler void Manager::createAll()
5454bfa7e7SMatt Spinler {
5534af47ffSMatt Spinler try
5634af47ffSMatt Spinler {
57259e7277SMatt Spinler auto objects = getManagedObjects(bus, LOGGING_BUSNAME, LOGGING_PATH);
5854bfa7e7SMatt Spinler
5954bfa7e7SMatt Spinler for (const auto& object : objects)
6054bfa7e7SMatt Spinler {
6154bfa7e7SMatt Spinler const auto& interfaces = object.second;
6254bfa7e7SMatt Spinler
63e6a51590SMatt Spinler auto propertyMap = interfaces.find(LOGGING_IFACE);
6454bfa7e7SMatt Spinler
6554bfa7e7SMatt Spinler if (propertyMap != interfaces.end())
6654bfa7e7SMatt Spinler {
67e6a51590SMatt Spinler createWithRestore(object.first, interfaces);
6854bfa7e7SMatt Spinler }
6954bfa7e7SMatt Spinler }
7054bfa7e7SMatt Spinler }
718123a713SPatrick Williams catch (const sdbusplus::exception_t& e)
7234af47ffSMatt Spinler {
7334af47ffSMatt Spinler log<level::ERR>("sdbusplus error getting logging managed objects",
7434af47ffSMatt Spinler entry("ERROR=%s", e.what()));
7534af47ffSMatt Spinler }
7634af47ffSMatt Spinler }
7754bfa7e7SMatt Spinler
createWithRestore(const std::string & objectPath,const DbusInterfaceMap & interfaces)78e6a51590SMatt Spinler void Manager::createWithRestore(const std::string& objectPath,
79e6a51590SMatt Spinler const DbusInterfaceMap& interfaces)
80e6a51590SMatt Spinler {
81e6a51590SMatt Spinler createObject(objectPath, interfaces);
82e6a51590SMatt Spinler
8360f53d86SMatt Spinler restoreCalloutObjects(objectPath, interfaces);
84e6a51590SMatt Spinler }
85e6a51590SMatt Spinler
create(const std::string & objectPath,const DbusInterfaceMap & interfaces)86259e7277SMatt Spinler void Manager::create(const std::string& objectPath,
87e6a51590SMatt Spinler const DbusInterfaceMap& interfaces)
8854bfa7e7SMatt Spinler {
89e6a51590SMatt Spinler createObject(objectPath, interfaces);
904a6ea6afSMatt Spinler
9152ee71bdSMatt Spinler createCalloutObjects(objectPath, interfaces);
92e6a51590SMatt Spinler }
93e6a51590SMatt Spinler
createObject(const std::string & objectPath,const DbusInterfaceMap & interfaces)94e6a51590SMatt Spinler void Manager::createObject(const std::string& objectPath,
95e6a51590SMatt Spinler const DbusInterfaceMap& interfaces)
96e6a51590SMatt Spinler {
974a6ea6afSMatt Spinler #ifdef USE_POLICY_INTERFACE
98e6a51590SMatt Spinler auto logInterface = interfaces.find(LOGGING_IFACE);
99e6a51590SMatt Spinler createPolicyInterface(objectPath, logInterface->second);
1004a6ea6afSMatt Spinler #endif
101e0017ebbSMatt Spinler }
102e0017ebbSMatt Spinler
erase(EntryID id)103a1390353SMatt Spinler void Manager::erase(EntryID id)
104a1390353SMatt Spinler {
10552ee71bdSMatt Spinler fs::remove_all(getSaveDir(id));
106677143bbSMatt Spinler childEntries.erase(id);
107a1390353SMatt Spinler entries.erase(id);
108a1390353SMatt Spinler }
109a1390353SMatt Spinler
addInterface(const std::string & objectPath,InterfaceType type,std::any & object)110491fc6f1SMatt Spinler void Manager::addInterface(const std::string& objectPath, InterfaceType type,
11154ea3ad8SMatt Spinler std::any& object)
112491fc6f1SMatt Spinler {
113491fc6f1SMatt Spinler auto id = getEntryID(objectPath);
114491fc6f1SMatt Spinler auto entry = entries.find(id);
115491fc6f1SMatt Spinler
116491fc6f1SMatt Spinler if (entry == entries.end())
117491fc6f1SMatt Spinler {
118491fc6f1SMatt Spinler InterfaceMap interfaces;
119491fc6f1SMatt Spinler interfaces.emplace(type, object);
120491fc6f1SMatt Spinler entries.emplace(id, std::move(interfaces));
121491fc6f1SMatt Spinler }
122491fc6f1SMatt Spinler else
123491fc6f1SMatt Spinler {
124491fc6f1SMatt Spinler entry->second.emplace(type, object);
125491fc6f1SMatt Spinler }
126491fc6f1SMatt Spinler }
127491fc6f1SMatt Spinler
addChildInterface(const std::string & objectPath,InterfaceType type,std::any & object)128677143bbSMatt Spinler void Manager::addChildInterface(const std::string& objectPath,
12954ea3ad8SMatt Spinler InterfaceType type, std::any& object)
130677143bbSMatt Spinler {
131677143bbSMatt Spinler auto id = getEntryID(objectPath);
132677143bbSMatt Spinler auto entry = childEntries.find(id);
133677143bbSMatt Spinler
134677143bbSMatt Spinler // childEntries is:
135677143bbSMatt Spinler // A map of error log entry IDs to:
136677143bbSMatt Spinler // a map of interface types to:
137677143bbSMatt Spinler // a vector of interface objects
138677143bbSMatt Spinler
139677143bbSMatt Spinler if (entry == childEntries.end())
140677143bbSMatt Spinler {
141677143bbSMatt Spinler ObjectList objects{object};
142677143bbSMatt Spinler InterfaceMapMulti interfaces;
143677143bbSMatt Spinler interfaces.emplace(type, std::move(objects));
144677143bbSMatt Spinler childEntries.emplace(id, std::move(interfaces));
145677143bbSMatt Spinler }
146677143bbSMatt Spinler else
147677143bbSMatt Spinler {
148677143bbSMatt Spinler auto i = entry->second.find(type);
149677143bbSMatt Spinler if (i == entry->second.end())
150677143bbSMatt Spinler {
1511b388099SMatt Spinler ObjectList objects{object};
152677143bbSMatt Spinler entry->second.emplace(type, objects);
153677143bbSMatt Spinler }
154677143bbSMatt Spinler else
155677143bbSMatt Spinler {
156677143bbSMatt Spinler i->second.emplace_back(object);
157677143bbSMatt Spinler }
158677143bbSMatt Spinler }
159677143bbSMatt Spinler }
160677143bbSMatt Spinler
1614a6ea6afSMatt Spinler #ifdef USE_POLICY_INTERFACE
createPolicyInterface(const std::string & objectPath,const DbusPropertyMap & properties)162259e7277SMatt Spinler void Manager::createPolicyInterface(const std::string& objectPath,
1634a6ea6afSMatt Spinler const DbusPropertyMap& properties)
1644a6ea6afSMatt Spinler {
1654a6ea6afSMatt Spinler auto values = policy::find(policies, properties);
1664a6ea6afSMatt Spinler
167c0763620SPatrick Williams auto object = std::make_shared<PolicyObject>(
168c0763620SPatrick Williams bus, objectPath.c_str(), PolicyObject::action::defer_emit);
1694a6ea6afSMatt Spinler
1704a6ea6afSMatt Spinler object->eventID(std::get<policy::EIDField>(values));
1714a6ea6afSMatt Spinler object->description(std::get<policy::MsgField>(values));
1724a6ea6afSMatt Spinler
1739bea4eafSMatt Spinler object->emit_object_added();
1749bea4eafSMatt Spinler
17554ea3ad8SMatt Spinler std::any anyObject = object;
1764a6ea6afSMatt Spinler
177491fc6f1SMatt Spinler addInterface(objectPath, InterfaceType::POLICY, anyObject);
1784a6ea6afSMatt Spinler }
1794a6ea6afSMatt Spinler #endif
1804a6ea6afSMatt Spinler
createCalloutObjects(const std::string & objectPath,const DbusInterfaceMap & interfaces)18152ee71bdSMatt Spinler void Manager::createCalloutObjects(const std::string& objectPath,
18252ee71bdSMatt Spinler const DbusInterfaceMap& interfaces)
18352ee71bdSMatt Spinler {
18452ee71bdSMatt Spinler // Use the associations property in the org.openbmc.Associations
18552ee71bdSMatt Spinler // interface to find any callouts. Then grab all properties on
18652ee71bdSMatt Spinler // the Asset interface for that object in the inventory to use
18752ee71bdSMatt Spinler // in our callout objects.
18852ee71bdSMatt Spinler
18952ee71bdSMatt Spinler auto associations = interfaces.find(ASSOC_IFACE);
19052ee71bdSMatt Spinler if (associations == interfaces.end())
19152ee71bdSMatt Spinler {
19252ee71bdSMatt Spinler return;
19352ee71bdSMatt Spinler }
19452ee71bdSMatt Spinler
19552ee71bdSMatt Spinler const auto& properties = associations->second;
1964c0e8945SMatt Spinler auto assocProperty = properties.find("Associations");
197b5af3a3fSPatrick Williams auto assocValue = std::get<AssociationsPropertyType>(assocProperty->second);
19852ee71bdSMatt Spinler
19952ee71bdSMatt Spinler auto id = getEntryID(objectPath);
20052ee71bdSMatt Spinler auto calloutNum = 0;
20152ee71bdSMatt Spinler DbusSubtree subtree;
20252ee71bdSMatt Spinler
20352ee71bdSMatt Spinler for (const auto& association : assocValue)
20452ee71bdSMatt Spinler {
20534af47ffSMatt Spinler try
20634af47ffSMatt Spinler {
20752ee71bdSMatt Spinler if (std::get<forwardPos>(association) != "callout")
20852ee71bdSMatt Spinler {
20952ee71bdSMatt Spinler continue;
21052ee71bdSMatt Spinler }
21152ee71bdSMatt Spinler
21252ee71bdSMatt Spinler auto callout = std::get<endpointPos>(association);
21352ee71bdSMatt Spinler
21452ee71bdSMatt Spinler if (subtree.empty())
21552ee71bdSMatt Spinler {
21652ee71bdSMatt Spinler subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
21752ee71bdSMatt Spinler if (subtree.empty())
21852ee71bdSMatt Spinler {
21952ee71bdSMatt Spinler break;
22052ee71bdSMatt Spinler }
22152ee71bdSMatt Spinler }
22252ee71bdSMatt Spinler
22352ee71bdSMatt Spinler auto service = getService(callout, ASSET_IFACE, subtree);
22452ee71bdSMatt Spinler if (service.empty())
22552ee71bdSMatt Spinler {
22652ee71bdSMatt Spinler continue;
22752ee71bdSMatt Spinler }
22852ee71bdSMatt Spinler
229*6a2b8956SPatrick Williams auto properties = getAllProperties(bus, service, callout,
230*6a2b8956SPatrick Williams ASSET_IFACE);
23152ee71bdSMatt Spinler if (properties.empty())
23252ee71bdSMatt Spinler {
23352ee71bdSMatt Spinler continue;
23452ee71bdSMatt Spinler }
23552ee71bdSMatt Spinler
23652ee71bdSMatt Spinler auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
23752ee71bdSMatt Spinler
23834af47ffSMatt Spinler auto object = std::make_shared<Callout>(
23934af47ffSMatt Spinler bus, calloutPath, callout, calloutNum,
24052ee71bdSMatt Spinler getLogTimestamp(interfaces), properties);
24152ee71bdSMatt Spinler
24252ee71bdSMatt Spinler auto dir = getCalloutSaveDir(id);
24352ee71bdSMatt Spinler if (!fs::exists(dir))
24452ee71bdSMatt Spinler {
24552ee71bdSMatt Spinler fs::create_directories(dir);
24652ee71bdSMatt Spinler }
24752ee71bdSMatt Spinler object->serialize(dir);
24852ee71bdSMatt Spinler
24954ea3ad8SMatt Spinler std::any anyObject = object;
25052ee71bdSMatt Spinler addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
25152ee71bdSMatt Spinler calloutNum++;
25252ee71bdSMatt Spinler }
2538123a713SPatrick Williams catch (const sdbusplus::exception_t& e)
25434af47ffSMatt Spinler {
25534af47ffSMatt Spinler log<level::ERR>("sdbusplus exception", entry("ERROR=%s", e.what()));
25634af47ffSMatt Spinler }
25734af47ffSMatt Spinler }
25852ee71bdSMatt Spinler }
25952ee71bdSMatt Spinler
restoreCalloutObjects(const std::string & objectPath,const DbusInterfaceMap & interfaces)26060f53d86SMatt Spinler void Manager::restoreCalloutObjects(const std::string& objectPath,
26160f53d86SMatt Spinler const DbusInterfaceMap& interfaces)
26260f53d86SMatt Spinler {
26360f53d86SMatt Spinler auto saveDir = getCalloutSaveDir(getEntryID(objectPath));
26460f53d86SMatt Spinler
26560f53d86SMatt Spinler if (!fs::exists(saveDir))
26660f53d86SMatt Spinler {
26760f53d86SMatt Spinler return;
26860f53d86SMatt Spinler }
26960f53d86SMatt Spinler
27060f53d86SMatt Spinler size_t id;
27160f53d86SMatt Spinler for (auto& f : fs::directory_iterator(saveDir))
27260f53d86SMatt Spinler {
27360f53d86SMatt Spinler try
27460f53d86SMatt Spinler {
27560f53d86SMatt Spinler id = std::stoul(f.path().filename());
27660f53d86SMatt Spinler }
277bf9ea8adSPatrick Williams catch (const std::exception& e)
27860f53d86SMatt Spinler {
27960f53d86SMatt Spinler log<level::ERR>("Invalid IBM logging callout save file. Deleting",
28060f53d86SMatt Spinler entry("FILE=%s", f.path().c_str()));
28160f53d86SMatt Spinler fs::remove(f.path());
28260f53d86SMatt Spinler continue;
28360f53d86SMatt Spinler }
28460f53d86SMatt Spinler
28560f53d86SMatt Spinler auto path = getCalloutObjectPath(objectPath, id);
28660f53d86SMatt Spinler auto callout = std::make_shared<Callout>(bus, path, id,
28760f53d86SMatt Spinler getLogTimestamp(interfaces));
28860f53d86SMatt Spinler if (callout->deserialize(saveDir))
28960f53d86SMatt Spinler {
29060f53d86SMatt Spinler callout->emit_object_added();
29154ea3ad8SMatt Spinler std::any anyObject = callout;
29260f53d86SMatt Spinler addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
29360f53d86SMatt Spinler }
29460f53d86SMatt Spinler }
29560f53d86SMatt Spinler }
29660f53d86SMatt Spinler
interfaceAdded(sdbusplus::message_t & msg)2978123a713SPatrick Williams void Manager::interfaceAdded(sdbusplus::message_t& msg)
298e0017ebbSMatt Spinler {
299e0017ebbSMatt Spinler sdbusplus::message::object_path path;
300e0017ebbSMatt Spinler DbusInterfaceMap interfaces;
301e0017ebbSMatt Spinler
302e0017ebbSMatt Spinler msg.read(path, interfaces);
303e0017ebbSMatt Spinler
304e0017ebbSMatt Spinler // Find the Logging.Entry interface with all of its properties
305e0017ebbSMatt Spinler // to pass to create().
306e6a51590SMatt Spinler if (interfaces.find(LOGGING_IFACE) != interfaces.end())
307e0017ebbSMatt Spinler {
308e6a51590SMatt Spinler create(path, interfaces);
309e0017ebbSMatt Spinler }
310e0017ebbSMatt Spinler }
311055da3bdSMatt Spinler
getLogTimestamp(const DbusInterfaceMap & interfaces)31252ee71bdSMatt Spinler uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
31352ee71bdSMatt Spinler {
31452ee71bdSMatt Spinler auto interface = interfaces.find(LOGGING_IFACE);
31552ee71bdSMatt Spinler if (interface != interfaces.end())
31652ee71bdSMatt Spinler {
31752ee71bdSMatt Spinler auto property = interface->second.find("Timestamp");
31852ee71bdSMatt Spinler if (property != interface->second.end())
31952ee71bdSMatt Spinler {
320b5af3a3fSPatrick Williams return std::get<uint64_t>(property->second);
32152ee71bdSMatt Spinler }
32252ee71bdSMatt Spinler }
32352ee71bdSMatt Spinler
32452ee71bdSMatt Spinler return 0;
32552ee71bdSMatt Spinler }
32652ee71bdSMatt Spinler
getSaveDir(EntryID id)32752ee71bdSMatt Spinler fs::path Manager::getSaveDir(EntryID id)
32852ee71bdSMatt Spinler {
32952ee71bdSMatt Spinler return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
33052ee71bdSMatt Spinler }
33152ee71bdSMatt Spinler
getCalloutSaveDir(EntryID id)33252ee71bdSMatt Spinler fs::path Manager::getCalloutSaveDir(EntryID id)
33352ee71bdSMatt Spinler {
33452ee71bdSMatt Spinler return getSaveDir(id) / "callouts";
33552ee71bdSMatt Spinler }
33652ee71bdSMatt Spinler
getCalloutObjectPath(const std::string & objectPath,uint32_t calloutNum)33752ee71bdSMatt Spinler std::string Manager::getCalloutObjectPath(const std::string& objectPath,
33852ee71bdSMatt Spinler uint32_t calloutNum)
33952ee71bdSMatt Spinler {
34052ee71bdSMatt Spinler return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
34152ee71bdSMatt Spinler }
34252ee71bdSMatt Spinler
interfaceRemoved(sdbusplus::message_t & msg)3438123a713SPatrick Williams void Manager::interfaceRemoved(sdbusplus::message_t& msg)
344055da3bdSMatt Spinler {
345055da3bdSMatt Spinler sdbusplus::message::object_path path;
346055da3bdSMatt Spinler DbusInterfaceList interfaces;
347055da3bdSMatt Spinler
348055da3bdSMatt Spinler msg.read(path, interfaces);
349055da3bdSMatt Spinler
350055da3bdSMatt Spinler // If the Logging.Entry interface was removed, then remove
351055da3bdSMatt Spinler // our object
352055da3bdSMatt Spinler
353055da3bdSMatt Spinler auto i = std::find(interfaces.begin(), interfaces.end(), LOGGING_IFACE);
354055da3bdSMatt Spinler
355055da3bdSMatt Spinler if (i != interfaces.end())
356055da3bdSMatt Spinler {
357a1390353SMatt Spinler erase(getEntryID(path));
358055da3bdSMatt Spinler }
359055da3bdSMatt Spinler }
36066e07073SMatt Spinler } // namespace logging
36166e07073SMatt Spinler } // namespace ibm
362