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 = 97 (action == Action::start) ? startMethod : 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