/** * 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 failedState = "failed"; constexpr auto startMethod = "StartUnit"; constexpr auto stopMethod = "StopUnit"; constexpr auto systemdService = "org.freedesktop.systemd1"; constexpr auto systemdObjPath = "/org/freedesktop/systemd1"; constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager"; constexpr auto systemdPropertyInterface = "org.freedesktop.DBus.Properties"; constexpr auto systemdUnitInterface = "org.freedesktop.systemd1.Unit"; void Monitor::analyze() { if (inFailedState(getSourceUnitPath())) { runTargetAction(); } } bool Monitor::inFailedState(const std::string& path) { std::variant property; auto method = bus.new_method_call(systemdService, path.c_str(), systemdPropertyInterface, "Get"); method.append(systemdUnitInterface, "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 = std::get(property); return (value == failedState); } std::string Monitor::getSourceUnitPath() { sdbusplus::message::object_path path; auto method = bus.new_method_call(systemdService, systemdObjPath, systemdInterface, "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 const auto* methodCall = (action == Action::start) ? startMethod : stopMethod; 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(systemdService, systemdObjPath, systemdInterface, 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