blob: 5bf40af2d875350c72229db8b092730ae4656c4c [file] [log] [blame]
Andrew Geisslere426b582020-05-28 12:40:55 -05001#include "systemd_target_signal.hpp"
2
Andrew Geissler234a3172019-08-09 14:30:02 -05003#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -05004#include <phosphor-logging/lg2.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -05005#include <sdbusplus/exception.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -05006#include <sdbusplus/server/manager.hpp>
7#include <sdeventplus/event.hpp>
Andrew Geissler234a3172019-08-09 14:30:02 -05008#include <xyz/openbmc_project/Common/error.hpp>
9
10namespace phosphor
11{
12namespace state
13{
14namespace manager
15{
16
17using phosphor::logging::elog;
Andrew Geissler8ffdb262021-09-20 15:25:19 -050018PHOSPHOR_LOG2_USING;
19
Andrew Geissler234a3172019-08-09 14:30:02 -050020using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
21
Andrew Geissler21d305e2022-02-11 16:49:51 -060022void SystemdTargetLogging::createBmcDump()
23{
24 auto method = this->bus.new_method_call(
25 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump/bmc",
26 "xyz.openbmc_project.Dump.Create", "CreateDump");
27 method.append(
28 std::vector<
29 std::pair<std::string, std::variant<std::string, uint64_t>>>());
30 try
31 {
32 this->bus.call_noreply(method);
33 }
34 catch (const sdbusplus::exception::exception& e)
35 {
36 error("Failed to create BMC dump, exception:{ERROR}", "ERROR", e);
37 // just continue, this is error path anyway so we're just collecting
38 // what we can
39 }
40}
41
Andrew Geissler73d2ac92022-02-17 16:55:50 -060042void SystemdTargetLogging::startBmcQuiesceTarget()
43{
44 auto method = this->bus.new_method_call(
45 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
46 "org.freedesktop.systemd1.Manager", "StartUnit");
47
48 // TODO: Enhance when needed to support multiple-bmc instance systems
49 method.append("obmc-bmc-service-quiesce@0.target");
50 method.append("replace");
51 try
52 {
53 this->bus.call_noreply(method);
54 }
55 catch (const sdbusplus::exception::exception& e)
56 {
57 error("Failed to start BMC quiesce target, exception:{ERROR}", "ERROR",
58 e);
59 // just continue, this is error path anyway so we're just doing what
60 // we can
61 }
62
63 return;
64}
65
Andrew Geissler8ffdb262021-09-20 15:25:19 -050066void SystemdTargetLogging::logError(const std::string& errorLog,
Andrew Geisslere6841032022-02-11 10:31:50 -060067 const std::string& result,
68 const std::string& unit)
Andrew Geissler234a3172019-08-09 14:30:02 -050069{
70 auto method = this->bus.new_method_call(
71 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
72 "xyz.openbmc_project.Logging.Create", "Create");
73 // Signature is ssa{ss}
Andrew Geissler8ffdb262021-09-20 15:25:19 -050074 method.append(errorLog);
Andrew Geissler234a3172019-08-09 14:30:02 -050075 method.append("xyz.openbmc_project.Logging.Entry.Level.Critical");
Andrew Geisslere6841032022-02-11 10:31:50 -060076 method.append(std::array<std::pair<std::string, std::string>, 2>(
77 {std::pair<std::string, std::string>({"SYSTEMD_RESULT", result}),
78 std::pair<std::string, std::string>({"SYSTEMD_UNIT", unit})}));
Andrew Geissler234a3172019-08-09 14:30:02 -050079 try
80 {
81 this->bus.call_noreply(method);
82 }
Patrick Williams0a675212021-09-02 09:49:43 -050083 catch (const sdbusplus::exception::exception& e)
Andrew Geissler234a3172019-08-09 14:30:02 -050084 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050085 error("Failed to create systemd target error, error:{ERROR_MSG}, "
86 "result:{RESULT}, exception:{ERROR}",
87 "ERROR_MSG", errorLog, "RESULT", result, "ERROR", e);
Andrew Geissler234a3172019-08-09 14:30:02 -050088 }
89}
90
Andrew Geisslerf3870c62022-02-10 16:15:28 -060091const std::string SystemdTargetLogging::processError(const std::string& unit,
92 const std::string& result)
Andrew Geissler234a3172019-08-09 14:30:02 -050093{
94 auto targetEntry = this->targetData.find(unit);
95 if (targetEntry != this->targetData.end())
96 {
97 // Check if its result matches any of our monitored errors
98 if (std::find(targetEntry->second.errorsToMonitor.begin(),
99 targetEntry->second.errorsToMonitor.end(),
100 result) != targetEntry->second.errorsToMonitor.end())
101 {
Andrew Geisslerad65b2d2021-09-21 12:53:29 -0500102 info(
103 "Monitored systemd unit has hit an error, unit:{UNIT}, result:{RESULT}",
104 "UNIT", unit, "RESULT", result);
Andrew Geisslerd59006a2022-03-21 14:25:08 -0500105
106 // Generate a BMC dump when a monitored target fails
107 createBmcDump();
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600108 return (targetEntry->second.errorToLog);
Andrew Geissler234a3172019-08-09 14:30:02 -0500109 }
110 }
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600111
112 // Check if it's in our list of services to monitor
113 if (std::find(this->serviceData.begin(), this->serviceData.end(), unit) !=
114 this->serviceData.end())
115 {
116 if (result == "failed")
117 {
118 info(
119 "Monitored systemd service has hit an error, unit:{UNIT}, result:{RESULT}",
120 "UNIT", unit, "RESULT", result);
Andrew Geissler21d305e2022-02-11 16:49:51 -0600121
122 // Generate a BMC dump when a critical service fails
123 createBmcDump();
Andrew Geissler73d2ac92022-02-17 16:55:50 -0600124 // Enter BMC Quiesce when a critical service fails
125 startBmcQuiesceTarget();
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600126 return (std::string{
127 "xyz.openbmc_project.State.Error.CriticalServiceFailure"});
128 }
129 }
130
131 return (std::string{});
Andrew Geissler234a3172019-08-09 14:30:02 -0500132}
133
134void SystemdTargetLogging::systemdUnitChange(sdbusplus::message::message& msg)
135{
136 uint32_t id;
137 sdbusplus::message::object_path objPath;
138 std::string unit{};
139 std::string result{};
140
141 msg.read(id, objPath, unit, result);
142
143 // In most cases it will just be success, in which case just return
144 if (result != "done")
145 {
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600146 const std::string error = processError(unit, result);
Andrew Geissler234a3172019-08-09 14:30:02 -0500147
148 // If this is a monitored error then log it
Andrew Geisslerf3870c62022-02-10 16:15:28 -0600149 if (!error.empty())
Andrew Geissler234a3172019-08-09 14:30:02 -0500150 {
Andrew Geisslere6841032022-02-11 10:31:50 -0600151 logError(error, result, unit);
Andrew Geissler234a3172019-08-09 14:30:02 -0500152 }
153 }
154 return;
155}
156
Andrew Geissler38605ee2019-11-11 16:01:56 -0600157void SystemdTargetLogging::processNameChangeSignal(
158 sdbusplus::message::message& msg)
159{
160 std::string name; // well-known
161 std::string old_owner; // unique-name
162 std::string new_owner; // unique-name
163
164 msg.read(name, old_owner, new_owner);
165
166 // Looking for systemd to be on dbus so we can call it
167 if (name == "org.freedesktop.systemd1")
168 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500169 info("org.freedesktop.systemd1 is now on dbus");
Andrew Geissler38605ee2019-11-11 16:01:56 -0600170 subscribeToSystemdSignals();
171 }
172 return;
173}
174
Andrew Geissler234a3172019-08-09 14:30:02 -0500175void SystemdTargetLogging::subscribeToSystemdSignals()
176{
177 auto method = this->bus.new_method_call(
178 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
179 "org.freedesktop.systemd1.Manager", "Subscribe");
180
181 try
182 {
183 this->bus.call(method);
184 }
Patrick Williams0a675212021-09-02 09:49:43 -0500185 catch (const sdbusplus::exception::exception& e)
Andrew Geissler234a3172019-08-09 14:30:02 -0500186 {
Andrew Geissler38605ee2019-11-11 16:01:56 -0600187 // If error indicates systemd is not on dbus yet then do nothing.
188 // The systemdNameChangeSignals callback will detect when it is on
189 // dbus and then call this function again
190 const std::string noDbus("org.freedesktop.DBus.Error.ServiceUnknown");
191 if (noDbus == e.name())
192 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500193 info("org.freedesktop.systemd1 not on dbus yet");
Andrew Geissler38605ee2019-11-11 16:01:56 -0600194 }
195 else
196 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500197 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR",
198 e);
Andrew Geissler38605ee2019-11-11 16:01:56 -0600199 elog<InternalFailure>();
200 }
201 return;
Andrew Geissler234a3172019-08-09 14:30:02 -0500202 }
203
Andrew Geissler38605ee2019-11-11 16:01:56 -0600204 // Call destructor on match callback since application is now subscribed to
205 // systemd signals
206 this->systemdNameOwnedChangedSignal.~match();
207
Andrew Geissler234a3172019-08-09 14:30:02 -0500208 return;
209}
210
211} // namespace manager
212} // namespace state
213} // namespace phosphor