diff options
author | Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com> | 2017-07-12 00:44:27 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2017-07-27 17:42:25 +0000 |
commit | 3f47524294fdca3a890e0fd4472aa2ef8be8049f (patch) | |
tree | 73e6f102e64e41559bbb1d68173aa9c93e494713 | |
parent | 8cf2f9a154665c94da59a734f0ef683397081c54 (diff) | |
download | phosphor-state-manager-3f47524294fdca3a890e0fd4472aa2ef8be8049f.tar.gz phosphor-state-manager-3f47524294fdca3a890e0fd4472aa2ef8be8049f.zip |
Persist user requested host state
Resolves openbmc/openbmc#1785
Change-Id: I5f23ce50dc357489c7b7eece8bab3bfd6a61ffae
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | host_state_manager.cpp | 93 | ||||
-rw-r--r-- | host_state_manager.hpp | 6 | ||||
-rw-r--r-- | host_state_manager_main.cpp | 6 | ||||
-rw-r--r-- | host_state_serialize.cpp | 68 | ||||
-rw-r--r-- | host_state_serialize.hpp | 37 |
7 files changed, 211 insertions, 10 deletions
diff --git a/Makefile.am b/Makefile.am index f15d970..0cea407 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,8 @@ sbin_PROGRAMS = \ phosphor_host_state_manager_SOURCES = \ host_state_manager.cpp \ - host_state_manager_main.cpp + host_state_manager_main.cpp \ + host_state_serialize.cpp phosphor_chassis_state_manager_SOURCES = \ chassis_state_manager.cpp \ @@ -29,7 +30,7 @@ generic_cxxflags = $(SYSTEMD_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) $(SDBUSP generic_ldflags = $(SYSTEMD_LIBS) $(PHOSPHOR_DBUS_INTERFACES_LIBS) $(SDBUSPLUS_LIBS) phosphor_host_state_manager_CXXFLAGS = $(generic_cxxflags) -phosphor_host_state_manager_LDFLAGS = $(generic_ldflags) +phosphor_host_state_manager_LDFLAGS = $(generic_ldflags) -lstdc++fs phosphor_chassis_state_manager_CXXFLAGS = $(generic_cxxflags) phosphor_chassis_state_manager_LDFLAGS = $(generic_ldflags) diff --git a/configure.ac b/configure.ac index b6ee1da..eb1ac58 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,12 @@ AC_ARG_VAR(HOST_RUNNING_FILE, [File to create if host is running]) AS_IF([test "x$HOST_RUNNING_FILE" == "x"], [HOST_RUNNING_FILE="/run/openbmc/host@%u-on"]) AC_DEFINE_UNQUOTED([HOST_RUNNING_FILE], ["$HOST_RUNNING_FILE"], [File to create if host is running]) +AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing requested host state.]) +AS_IF([test "x$HOST_STATE_PERSIST_PATH" == "x"], \ + [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/requestedHostTransition"]) +AC_DEFINE_UNQUOTED([HOST_STATE_PERSIST_PATH], ["$HOST_STATE_PERSIST_PATH"], \ + [Path of file for storing requested host state.]) + # Check for header files. AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd developement package required])]) AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) diff --git a/host_state_manager.cpp b/host_state_manager.cpp index fd1d056..da42918 100644 --- a/host_state_manager.cpp +++ b/host_state_manager.cpp @@ -4,7 +4,12 @@ #include <systemd/sd-bus.h> #include <sdbusplus/server.hpp> #include <phosphor-logging/log.hpp> +#include <experimental/filesystem> +#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp> #include "host_state_manager.hpp" +#include "host_state_serialize.hpp" +#include "config.h" + namespace phosphor { @@ -17,6 +22,7 @@ namespace manager namespace server = sdbusplus::xyz::openbmc_project::State::server; using namespace phosphor::logging; +namespace fs = std::experimental::filesystem; // host-shutdown notifies host of shutdown and that leads to host-stop being // called so initiate a host shutdown with the -shutdown target and consider the @@ -51,6 +57,11 @@ constexpr auto REBOOTCOUNTER_INTERFACE("org.openbmc.SensorValue"); constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties"; constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit"; +constexpr auto SETTINGS_INTERFACE = + "xyz.openbmc_project.Control.Power.RestorePolicy"; +constexpr auto SETTINGS_SERVICE_ROOT = "/"; +constexpr auto SETTINGS_HOST_STATE_RESTORE = "PowerRestorePolicy"; + // TODO openbmc/openbmc#1646 - boot count needs to be defined in 1 place constexpr auto DEFAULT_BOOTCOUNT = 3; @@ -92,13 +103,77 @@ void Host::determineInitialState() server::Host::requestedHostTransition(Transition::Off); } - // Set transition initially to Off - // TODO - Eventually need to restore this from persistent storage - server::Host::requestedHostTransition(Transition::Off); + auto restore = getStateRestoreSetting(); + + if ((!restore) || (!deserialize(HOST_STATE_PERSIST_PATH,*this))) + { + //set to default value. + server::Host::requestedHostTransition(Transition::Off); + } return; } +bool Host::getStateRestoreSetting() const +{ + using namespace phosphor::logging; + auto depth = 0; + auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, + MAPPER_PATH, + MAPPER_INTERFACE, + "GetSubTree"); + mapperCall.append(SETTINGS_SERVICE_ROOT); + mapperCall.append(depth); + mapperCall.append(std::vector<std::string>({SETTINGS_INTERFACE})); + + auto mapperResponseMsg = bus.call(mapperCall); + if (mapperResponseMsg.is_method_error()) + { + log<level::ERR>("Error in mapper call"); + return false; + } + + using MapperResponseType = std::map<std::string, + std::map<std::string, std::vector<std::string>>>; + MapperResponseType mapperResponse; + mapperResponseMsg.read(mapperResponse); + if (mapperResponse.empty()) + { + log<level::ERR>("Invalid response from mapper"); + return false; + } + + auto& settingsPath = mapperResponse.begin()->first; + auto& service = mapperResponse.begin()->second.begin()->first; + + auto cmdMsg = bus.new_method_call(service.c_str(), + settingsPath.c_str(), + SYSTEMD_PROPERTY_IFACE, + "Get"); + cmdMsg.append(SETTINGS_INTERFACE); + cmdMsg.append(SETTINGS_HOST_STATE_RESTORE); + + auto response = bus.call(cmdMsg); + if (response.is_method_error()) + { + log<level::ERR>("Error in fetching host state restore settings"); + return false; + } + + sdbusplus::message::variant<std::string> result; + response.read(result); + + using RestorePolicy = sdbusplus::xyz::openbmc_project::Control:: + Power::server::RestorePolicy; + + if (RestorePolicy::convertPolicyFromString(result.get<std::string>()) == + RestorePolicy::Policy::Restore) + { + return true; + } + return false; +} + void Host::executeTransition(Transition tranReq) { auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second; @@ -130,7 +205,7 @@ bool Host::stateActive(const std::string& target) auto result = this->bus.call(method); //Check that the bus call didn't result in an error - if(result.is_method_error()) + if (result.is_method_error()) { log<level::ERR>("Error in bus call - could not resolve GetUnit for:", entry(" %s", SYSTEMD_INTERFACE)); @@ -149,7 +224,7 @@ bool Host::stateActive(const std::string& target) result = this->bus.call(method); //Check that the bus call didn't result in an error - if(result.is_method_error()) + if (result.is_method_error()) { log<level::ERR>("Error in bus call - could not resolve Get for:", entry(" %s", SYSTEMD_PROPERTY_IFACE)); @@ -158,7 +233,7 @@ bool Host::stateActive(const std::string& target) result.read(currentState); - if(currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE) + if (currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE) { //False - not active return false; @@ -249,7 +324,7 @@ bool Host::isAutoReboot() if (strParam == "yes") { - if( rebootCounterParam > 0) + if ( rebootCounterParam > 0) { // Reduce BOOTCOUNT by 1 log<level::INFO>("Auto reboot enabled. " @@ -355,7 +430,9 @@ Host::Transition Host::requestedHostTransition(Transition value) } executeTransition(tranReq); - return server::Host::requestedHostTransition(value); + auto retVal = server::Host::requestedHostTransition(value); + serialize(*this); + return retVal; } Host::HostState Host::currentHostState(HostState value) diff --git a/host_state_manager.hpp b/host_state_manager.hpp index de9d5fb..af4fa15 100644 --- a/host_state_manager.hpp +++ b/host_state_manager.hpp @@ -127,6 +127,12 @@ class Host : public HostInherit */ void sysStateChange(sdbusplus::message::message& msg); + /** @brief Determine whether restoring of host requested state is enabled + * + * @return boolean corresponding to restore setting + */ + bool getStateRestoreSetting() const; + /** @brief Persistent sdbusplus DBus bus connection. */ sdbusplus::bus::bus& bus; diff --git a/host_state_manager_main.cpp b/host_state_manager_main.cpp index 2084f36..12d5e9a 100644 --- a/host_state_manager_main.cpp +++ b/host_state_manager_main.cpp @@ -2,11 +2,14 @@ #include <iostream> #include <exception> #include <sdbusplus/bus.hpp> +#include <experimental/filesystem> #include "config.h" #include "host_state_manager.hpp" int main(int argc, char *argv[]) { + namespace fs = std::experimental::filesystem; + auto bus = sdbusplus::bus::new_default(); // For now, we only have one instance of the host @@ -19,6 +22,9 @@ int main(int argc, char *argv[]) HOST_BUSNAME, objPathInst.c_str()); + auto dir = fs::path(HOST_STATE_PERSIST_PATH).parent_path(); + fs::create_directories(dir); + bus.request_name(HOST_BUSNAME); while(true) diff --git a/host_state_serialize.cpp b/host_state_serialize.cpp new file mode 100644 index 0000000..d5a3a98 --- /dev/null +++ b/host_state_serialize.cpp @@ -0,0 +1,68 @@ +#include <cereal/types/string.hpp> +#include <cereal/types/vector.hpp> +#include <cereal/types/tuple.hpp> +#include <cereal/archives/json.hpp> +#include <fstream> +#include "host_state_serialize.hpp" +#include "host_state_manager.hpp" + +namespace phosphor +{ +namespace state +{ +namespace manager +{ +/** @brief Function required by Cereal to perform serialization. + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] archive - reference to Cereal archive. + * @param[in] host - const reference to host. + */ +template<class Archive> +void save(Archive& archive, const Host& host) +{ + archive(convertForMessage(host.sdbusplus::xyz::openbmc_project:: + State::server::Host::requestedHostTransition())); +} + +/** @brief Function required by Cereal to perform deserialization. + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] archive - reference to Cereal archive. + * @param[in] host - reference to host. + */ +template<class Archive> +void load(Archive& archive, Host& host) +{ + using namespace + sdbusplus::xyz::openbmc_project::State::server; + + Host::Transition requestedHostTransition{}; + + std::string str; + archive(str); + requestedHostTransition = Host::convertTransitionFromString( + str); + host.requestedHostTransition(requestedHostTransition); +} + +fs::path serialize(const Host& host, const fs::path& dir) +{ + std::ofstream os(dir.c_str(), std::ios::binary); + cereal::JSONOutputArchive oarchive(os); + oarchive(host); + return dir; +} + +bool deserialize(const fs::path& path, Host& host) +{ + if (fs::exists(path)) + { + std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); + cereal::JSONInputArchive iarchive(is); + iarchive(host); + return true; + } + return false; +} +} //namespace manager +} // namespace state +} // namespace phosphor diff --git a/host_state_serialize.hpp b/host_state_serialize.hpp new file mode 100644 index 0000000..0bc7684 --- /dev/null +++ b/host_state_serialize.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include <string> +#include <vector> +#include <experimental/filesystem> +#include "host_state_manager.hpp" +#include "config.h" + +namespace phosphor +{ +namespace state +{ +namespace manager +{ + +namespace fs = std::experimental::filesystem; + +/** @brief Serialize and persist requested host state + * @param[in] host - const reference to host state. + * @param[in] dir - pathname of file where the serialized host state will + * be placed. + * @return fs::path - pathname of persisted requested host state. + */ +fs::path serialize(const Host& host, + const fs::path& dir = fs::path(HOST_STATE_PERSIST_PATH)); + +/** @brief Deserialze a persisted requested host state. + * @param[in] path - pathname of persisted host state file + * @param[in] host - reference to host state object which is the target of + * deserialization. + * @return bool - true if the deserialization was successful, false otherwise. + */ +bool deserialize(const fs::path& path, Host& host); + +} // namespace manager +} // namespace state +} // namespace phosphor |