summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>2017-07-12 00:44:27 -0500
committerPatrick Williams <patrick@stwcx.xyz>2017-07-27 17:42:25 +0000
commit3f47524294fdca3a890e0fd4472aa2ef8be8049f (patch)
tree73e6f102e64e41559bbb1d68173aa9c93e494713
parent8cf2f9a154665c94da59a734f0ef683397081c54 (diff)
downloadphosphor-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.am5
-rw-r--r--configure.ac6
-rw-r--r--host_state_manager.cpp93
-rw-r--r--host_state_manager.hpp6
-rw-r--r--host_state_manager_main.cpp6
-rw-r--r--host_state_serialize.cpp68
-rw-r--r--host_state_serialize.hpp37
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
OpenPOWER on IntegriCloud