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