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