/** * Copyright © 2017 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "monitor.hpp" #include namespace phosphor { namespace unit { namespace failure { using namespace phosphor::logging; constexpr auto FAILED_STATE = "failed"; constexpr auto START_METHOD = "StartUnit"; constexpr auto STOP_METHOD = "StopUnit"; constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; constexpr auto SYSTEMD_PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; constexpr auto SYSTEMD_UNIT_INTERFACE = "org.freedesktop.systemd1.Unit"; void Monitor::analyze() { if (inFailedState(std::move(getSourceUnitPath()))) { runTargetAction(); } } bool Monitor::inFailedState(const std::string&& path) { sdbusplus::message::variant property; auto method = bus.new_method_call(SYSTEMD_SERVICE, path.c_str(), SYSTEMD_PROPERTY_INTERFACE, "Get"); method.append(SYSTEMD_UNIT_INTERFACE, "ActiveState"); auto reply = bus.call(method); if (reply.is_method_error()) { log("Failed reading ActiveState DBus property", entry("UNIT=%s", source.c_str())); // TODO openbmc/openbmc#851 - Once available, throw returned error throw std::runtime_error("Failed reading ActiveState DBus property"); } reply.read(property); auto value = sdbusplus::message::variant_ns::get(property); return (value == FAILED_STATE); } std::string Monitor::getSourceUnitPath() { sdbusplus::message::object_path path; auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "GetUnit"); method.append(source); auto reply = bus.call(method); if (reply.is_method_error()) { log("Failed GetUnit DBus method call", entry("UNIT=%s", source.c_str())); // TODO openbmc/openbmc#851 - Once available, throw returned error throw std::runtime_error("Failed GetUnit DBus method call"); } reply.read(path); return static_cast(path); } void Monitor::runTargetAction() { // Start or stop the target unit auto methodCall = (action == Action::start) ? START_METHOD : STOP_METHOD; log("The source unit is in failed state, " "running target action", entry("SOURCE=%s", source.c_str()), entry("TARGET=%s", target.c_str()), entry("ACTION=%s", methodCall)); auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, methodCall); method.append(target); method.append("replace"); auto reply = bus.call(method); if (reply.is_method_error()) { log("Failed to run action on the target unit", entry("UNIT=%s", target.c_str())); // TODO openbmc/openbmc#851 - Once available, throw returned error throw std::runtime_error("Failed to run action on the target unit"); } } } // namespace failure } // namespace unit } // namespace phosphor