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