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(std::move(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 auto methodCall = (action == Action::start) ? startMethod : stopMethod; 97 98 log<level::INFO>("The source unit is in failed state, " 99 "running target action", 100 entry("SOURCE=%s", source.c_str()), 101 entry("TARGET=%s", target.c_str()), 102 entry("ACTION=%s", methodCall)); 103 104 auto method = this->bus.new_method_call(systemdService, systemdObjPath, 105 systemdInterface, methodCall); 106 method.append(target); 107 method.append("replace"); 108 109 auto reply = bus.call(method); 110 111 if (reply.is_method_error()) 112 { 113 log<level::ERR>("Failed to run action on the target unit", 114 entry("UNIT=%s", target.c_str())); 115 // TODO openbmc/openbmc#851 - Once available, throw returned error 116 throw std::runtime_error("Failed to run action on the target unit"); 117 } 118 } 119 } // namespace failure 120 } // namespace unit 121 } // namespace phosphor 122