xref: /openbmc/phosphor-objmgr/fail-monitor/monitor.cpp (revision 167e2379abb36d8c813fed0ee1da3b79715d477a)
1 /**
2  * Copyright © 2017 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 <phosphor-logging/log.hpp>
17 #include "monitor.hpp"
18 
19 namespace phosphor
20 {
21 namespace unit
22 {
23 namespace failure
24 {
25 
26 using namespace phosphor::logging;
27 
28 constexpr auto FAILED_STATE = "failed";
29 constexpr auto START_METHOD = "StartUnit";
30 constexpr auto STOP_METHOD = "StopUnit";
31 
32 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
33 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
34 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
35 constexpr auto SYSTEMD_PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
36 constexpr auto SYSTEMD_UNIT_INTERFACE = "org.freedesktop.systemd1.Unit";
37 
38 void Monitor::analyze()
39 {
40     if (inFailedState(std::move(getSourceUnitPath())))
41     {
42         runTargetAction();
43     }
44 }
45 
46 bool Monitor::inFailedState(const std::string&& path)
47 {
48     sdbusplus::message::variant<std::string> property;
49 
50     auto method = bus.new_method_call(SYSTEMD_SERVICE, path.c_str(),
51                                       SYSTEMD_PROPERTY_INTERFACE, "Get");
52 
53     method.append(SYSTEMD_UNIT_INTERFACE, "ActiveState");
54 
55     auto reply = bus.call(method);
56     if (reply.is_method_error())
57     {
58         log<level::ERR>("Failed reading ActiveState DBus property",
59                         entry("UNIT=%s", source.c_str()));
60         // TODO openbmc/openbmc#851 - Once available, throw returned error
61         throw std::runtime_error("Failed reading ActiveState DBus property");
62     }
63 
64     reply.read(property);
65 
66     auto value = sdbusplus::message::variant_ns::get<std::string>(property);
67     return (value == FAILED_STATE);
68 }
69 
70 std::string Monitor::getSourceUnitPath()
71 {
72     sdbusplus::message::object_path path;
73 
74     auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
75                                       SYSTEMD_INTERFACE, "GetUnit");
76     method.append(source);
77     auto reply = bus.call(method);
78 
79     if (reply.is_method_error())
80     {
81         log<level::ERR>("Failed GetUnit DBus method call",
82                         entry("UNIT=%s", source.c_str()));
83         // TODO openbmc/openbmc#851 - Once available, throw returned error
84         throw std::runtime_error("Failed GetUnit DBus method call");
85     }
86 
87     reply.read(path);
88 
89     return static_cast<std::string>(path);
90 }
91 
92 void Monitor::runTargetAction()
93 {
94     // Start or stop the target unit
95     auto methodCall = (action == Action::start) ? START_METHOD : STOP_METHOD;
96 
97     log<level::INFO>("The source unit is in failed state, "
98                      "running target action",
99                      entry("SOURCE=%s", source.c_str()),
100                      entry("TARGET=%s", target.c_str()),
101                      entry("ACTION=%s", methodCall));
102 
103     auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
104                                             SYSTEMD_INTERFACE, methodCall);
105     method.append(target);
106     method.append("replace");
107 
108     auto reply = bus.call(method);
109 
110     if (reply.is_method_error())
111     {
112         log<level::ERR>("Failed to run action on the target unit",
113                         entry("UNIT=%s", target.c_str()));
114         // TODO openbmc/openbmc#851 - Once available, throw returned error
115         throw std::runtime_error("Failed to run action on the target unit");
116     }
117 }
118 }
119 }
120 }
121