blob: 2014045f77784cd905d7a04c5bc0979efed0c8a0 [file] [log] [blame]
Andrew Geisslere426b582020-05-28 12:40:55 -05001#include "systemd_target_signal.hpp"
2
Andrew Geissler55e96ac2022-04-19 11:44:53 -04003#include "utils.hpp"
4
Andrew Geissler234a3172019-08-09 14:30:02 -05005#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -05006#include <phosphor-logging/lg2.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -05007#include <sdbusplus/exception.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -05008#include <sdbusplus/server/manager.hpp>
9#include <sdeventplus/event.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -050010#include <xyz/openbmc_project/Common/error.hpp>
Patrick Williams9a286db2024-01-17 06:29:47 -060011#include <xyz/openbmc_project/Logging/Create/client.hpp>
12#include <xyz/openbmc_project/Logging/Entry/client.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -050013
14namespace phosphor
15{
16namespace state
17{
18namespace manager
19{
20
21using phosphor::logging::elog;
Andrew Geissler8ffdb262021-09-20 15:25:19 -050022PHOSPHOR_LOG2_USING;
23
Andrew Geissler234a3172019-08-09 14:30:02 -050024using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
25
Patrick Williams9a286db2024-01-17 06:29:47 -060026using LoggingCreate =
27 sdbusplus::client::xyz::openbmc_project::logging::Create<>;
28using LoggingEntry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
29
Andrew Geissler73d2ac92022-02-17 16:55:50 -060030void SystemdTargetLogging::startBmcQuiesceTarget()
31{
32 auto method = this->bus.new_method_call(
33 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
34 "org.freedesktop.systemd1.Manager", "StartUnit");
35
36 // TODO: Enhance when needed to support multiple-bmc instance systems
37 method.append("obmc-bmc-service-quiesce@0.target");
38 method.append("replace");
39 try
40 {
41 this->bus.call_noreply(method);
42 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -050043 catch (const sdbusplus::exception_t& e)
Andrew Geissler73d2ac92022-02-17 16:55:50 -060044 {
45 error("Failed to start BMC quiesce target, exception:{ERROR}", "ERROR",
46 e);
47 // just continue, this is error path anyway so we're just doing what
48 // we can
49 }
50
51 return;
52}
53
Andrew Geissler8ffdb262021-09-20 15:25:19 -050054void SystemdTargetLogging::logError(const std::string& errorLog,
Andrew Geisslere6841032022-02-11 10:31:50 -060055 const std::string& result,
56 const std::string& unit)
Andrew Geissler234a3172019-08-09 14:30:02 -050057{
Patrick Williams9a286db2024-01-17 06:29:47 -060058 auto method = this->bus.new_method_call(LoggingCreate::default_service,
59 LoggingCreate::instance_path,
60 LoggingCreate::interface, "Create");
Andrew Geissler234a3172019-08-09 14:30:02 -050061 // Signature is ssa{ss}
Patrick Williams9a286db2024-01-17 06:29:47 -060062 method.append(
63 errorLog, LoggingEntry::Level::Critical,
64 std::array<std::pair<std::string, std::string>, 2>(
65 {std::pair<std::string, std::string>({"SYSTEMD_RESULT", result}),
66 std::pair<std::string, std::string>({"SYSTEMD_UNIT", unit})}));
Andrew Geissler234a3172019-08-09 14:30:02 -050067 try
68 {
69 this->bus.call_noreply(method);
70 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -050071 catch (const sdbusplus::exception_t& e)
Andrew Geissler234a3172019-08-09 14:30:02 -050072 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050073 error("Failed to create systemd target error, error:{ERROR_MSG}, "
74 "result:{RESULT}, exception:{ERROR}",
75 "ERROR_MSG", errorLog, "RESULT", result, "ERROR", e);
Andrew Geissler234a3172019-08-09 14:30:02 -050076 }
77}
78
Andrew Geisslerf3870c62022-02-10 16:15:28 -060079const std::string SystemdTargetLogging::processError(const std::string& unit,
80 const std::string& result)
Andrew Geissler234a3172019-08-09 14:30:02 -050081{
82 auto targetEntry = this->targetData.find(unit);
83 if (targetEntry != this->targetData.end())
84 {
85 // Check if its result matches any of our monitored errors
86 if (std::find(targetEntry->second.errorsToMonitor.begin(),
87 targetEntry->second.errorsToMonitor.end(),
88 result) != targetEntry->second.errorsToMonitor.end())
89 {
Andrew Geisslerad65b2d2021-09-21 12:53:29 -050090 info(
91 "Monitored systemd unit has hit an error, unit:{UNIT}, result:{RESULT}",
92 "UNIT", unit, "RESULT", result);
Andrew Geisslerd59006a2022-03-21 14:25:08 -050093
94 // Generate a BMC dump when a monitored target fails
Andrew Geissler55e96ac2022-04-19 11:44:53 -040095 utils::createBmcDump(this->bus);
Andrew Geisslerf3870c62022-02-10 16:15:28 -060096 return (targetEntry->second.errorToLog);
Andrew Geissler234a3172019-08-09 14:30:02 -050097 }
98 }
Andrew Geisslerf3870c62022-02-10 16:15:28 -060099
100 // Check if it's in our list of services to monitor
101 if (std::find(this->serviceData.begin(), this->serviceData.end(), unit) !=
102 this->serviceData.end())
103 {
104 if (result == "failed")
105 {
106 info(
107 "Monitored systemd service has hit an error, unit:{UNIT}, result:{RESULT}",
108 "UNIT", unit, "RESULT", result);
Andrew Geissler21d305e2022-02-11 16:49:51 -0600109
110 // Generate a BMC dump when a critical service fails
Andrew Geissler55e96ac2022-04-19 11:44:53 -0400111 utils::createBmcDump(this->bus);
Andrew Geissler73d2ac92022-02-17 16:55:50 -0600112 // Enter BMC Quiesce when a critical service fails
113 startBmcQuiesceTarget();
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600114 return (std::string{
115 "xyz.openbmc_project.State.Error.CriticalServiceFailure"});
116 }
117 }
118
119 return (std::string{});
Andrew Geissler234a3172019-08-09 14:30:02 -0500120}
121
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500122void SystemdTargetLogging::systemdUnitChange(sdbusplus::message_t& msg)
Andrew Geissler234a3172019-08-09 14:30:02 -0500123{
124 uint32_t id;
125 sdbusplus::message::object_path objPath;
126 std::string unit{};
127 std::string result{};
128
129 msg.read(id, objPath, unit, result);
130
131 // In most cases it will just be success, in which case just return
132 if (result != "done")
133 {
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600134 const std::string error = processError(unit, result);
Andrew Geissler234a3172019-08-09 14:30:02 -0500135
136 // If this is a monitored error then log it
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600137 if (!error.empty())
Andrew Geissler234a3172019-08-09 14:30:02 -0500138 {
Andrew Geisslere6841032022-02-11 10:31:50 -0600139 logError(error, result, unit);
Andrew Geissler234a3172019-08-09 14:30:02 -0500140 }
141 }
142 return;
143}
144
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500145void SystemdTargetLogging::processNameChangeSignal(sdbusplus::message_t& msg)
Andrew Geissler38605ee2019-11-11 16:01:56 -0600146{
147 std::string name; // well-known
148 std::string old_owner; // unique-name
149 std::string new_owner; // unique-name
150
151 msg.read(name, old_owner, new_owner);
152
153 // Looking for systemd to be on dbus so we can call it
154 if (name == "org.freedesktop.systemd1")
155 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500156 info("org.freedesktop.systemd1 is now on dbus");
Andrew Geissler38605ee2019-11-11 16:01:56 -0600157 subscribeToSystemdSignals();
158 }
159 return;
160}
161
Andrew Geissler234a3172019-08-09 14:30:02 -0500162void SystemdTargetLogging::subscribeToSystemdSignals()
163{
164 auto method = this->bus.new_method_call(
165 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
166 "org.freedesktop.systemd1.Manager", "Subscribe");
167
168 try
169 {
170 this->bus.call(method);
171 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500172 catch (const sdbusplus::exception_t& e)
Andrew Geissler234a3172019-08-09 14:30:02 -0500173 {
Andrew Geissler38605ee2019-11-11 16:01:56 -0600174 // If error indicates systemd is not on dbus yet then do nothing.
175 // The systemdNameChangeSignals callback will detect when it is on
176 // dbus and then call this function again
177 const std::string noDbus("org.freedesktop.DBus.Error.ServiceUnknown");
178 if (noDbus == e.name())
179 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500180 info("org.freedesktop.systemd1 not on dbus yet");
Andrew Geissler38605ee2019-11-11 16:01:56 -0600181 }
182 else
183 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500184 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR",
185 e);
Andrew Geissler38605ee2019-11-11 16:01:56 -0600186 elog<InternalFailure>();
187 }
188 return;
Andrew Geissler234a3172019-08-09 14:30:02 -0500189 }
190
Andrew Geissler38605ee2019-11-11 16:01:56 -0600191 // Call destructor on match callback since application is now subscribed to
192 // systemd signals
193 this->systemdNameOwnedChangedSignal.~match();
194
Andrew Geissler234a3172019-08-09 14:30:02 -0500195 return;
196}
197
198} // namespace manager
199} // namespace state
200} // namespace phosphor