Use systemd targets to track host states
Change-Id: I5ab174d945c1dfb265a02f9095d3eaeb0ba562db
Signed-off-by: Andrew Geissler <andrewg@us.ibm.com>
diff --git a/host_state_manager.cpp b/host_state_manager.cpp
index e16d0de..2d35886 100644
--- a/host_state_manager.cpp
+++ b/host_state_manager.cpp
@@ -17,11 +17,14 @@
using namespace phosphor::logging;
+constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-chassis-stop@0.target";
+constexpr auto HOST_STATE_POWERON_TGT = "obmc-chassis-start@0.target";
+
/* Map a transition to it's systemd target */
const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
{
- {server::Host::Transition::Off, "obmc-chassis-stop@0.target"},
- {server::Host::Transition::On, "obmc-chassis-start@0.target"}
+ {server::Host::Transition::Off, HOST_STATE_POWEROFF_TGT},
+ {server::Host::Transition::On, HOST_STATE_POWERON_TGT}
};
constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
@@ -33,12 +36,22 @@
constexpr auto SYSTEM_INTERFACE = SYSTEM_SERVICE;
/* Map a system state to the HostState */
-/* TODO:Issue 774 - Use systemd target signals to control host states */
const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
{"HOST_BOOTING", server::Host::HostState::Running},
{"HOST_POWERED_OFF", server::Host::HostState::Off}
};
+void Host::subscribeToSystemdSignals()
+{
+ auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
+ SYSTEMD_OBJ_PATH,
+ SYSTEMD_INTERFACE,
+ "Subscribe");
+ this->bus.call_noreply(method);
+
+ return;
+}
+
// TODO - Will be rewritten once sdbusplus client bindings are in place
// and persistent storage design is in place
void Host::determineInitialState()
@@ -90,40 +103,49 @@
method.append(sysdUnit);
method.append("replace");
- this->bus.call(method);
+ this->bus.call_noreply(method);
return;
}
-int Host::handleSysStateChange(sd_bus_message *msg, void *usrData,
- sd_bus_error *retError)
+int Host::sysStateChangeSignal(sd_bus_message *msg, void *userData,
+ sd_bus_error *retError)
{
- const char *newState = nullptr;
- auto sdPlusMsg = sdbusplus::message::message(msg);
- sdPlusMsg.read(newState);
+ return static_cast<Host*>(userData)->sysStateChange(msg, retError);
+}
- auto it = SYS_HOST_STATE_TABLE.find(newState);
- if(it != SYS_HOST_STATE_TABLE.end())
+int Host::sysStateChange(sd_bus_message* msg,
+ sd_bus_error* retError)
+{
+ uint32_t newStateID {};
+ sdbusplus::message::object_path newStateObjPath;
+ std::string newStateUnit{};
+ std::string newStateResult{};
+
+ auto sdPlusMsg = sdbusplus::message::message(msg);
+ //Read the msg and populate each variable
+ sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+ if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
+ (newStateResult == "done"))
{
- // This is a state change we're interested in so process it
- Host::HostState gotoState = it->second;
- // Grab the host object instance from the userData
- auto hostInst = static_cast<Host*>(usrData);
- hostInst->currentHostState(gotoState);
+ log<level::INFO>("Recieved signal that host is off");
+ this->currentHostState(server::Host::HostState::Off);
// Check if we need to start a new transition (i.e. a Reboot)
- if((gotoState == server::Host::HostState::Off) &&
- (hostInst->server::Host::requestedHostTransition() ==
- Transition::Reboot))
+ if(this->server::Host::requestedHostTransition() ==
+ Transition::Reboot)
{
log<level::DEBUG>("Reached intermediate state, going to next");
- hostInst->executeTransition(server::Host::Transition::On);
- }
- else
- {
- log<level::DEBUG>("Reached final state");
+ this->executeTransition(server::Host::Transition::On);
}
}
+ else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
+ (newStateResult == "done"))
+ {
+ log<level::INFO>("Recieved signal that host is running");
+ this->currentHostState(server::Host::HostState::Running);
+ }
return 0;
}
diff --git a/host_state_manager.hpp b/host_state_manager.hpp
index 515409e..597efa5 100644
--- a/host_state_manager.hpp
+++ b/host_state_manager.hpp
@@ -36,11 +36,17 @@
sdbusplus::xyz::openbmc_project::State::server::Host>(
bus, objPath, true),
bus(bus),
- stateSignal(bus,
- "type='signal',member='GotoSystemState'",
- handleSysStateChange,
- this)
+ systemdSignals(bus,
+ "type='signal',"
+ "member='JobRemoved',"
+ "path='/org/freedesktop/systemd1',"
+ "interface='org.freedesktop.systemd1.Manager'",
+ sysStateChangeSignal,
+ this)
{
+ // Enable systemd signals
+ subscribeToSystemdSignals();
+
// Will throw exception on fail
determineInitialState();
@@ -48,13 +54,6 @@
this->emit_object_added();
}
- /**
- * @brief Determine initial host state and set internally
- *
- * @return Will throw exceptions on failure
- **/
- void determineInitialState();
-
/** @brief Set value of HostTransition */
Transition requestedHostTransition(Transition value) override;
@@ -62,6 +61,22 @@
HostState currentHostState(HostState value) override;
private:
+ /**
+ * @brief subscribe to the systemd signals
+ *
+ * This object needs to capture when it's systemd targets complete
+ * so it can keep it's state updated
+ *
+ **/
+ void subscribeToSystemdSignals();
+
+ /**
+ * @brief Determine initial host state and set internally
+ *
+ * @return Will throw exceptions on failure
+ **/
+ void determineInitialState();
+
/** @brief Execute the transition request
*
* This function assumes the state has been validated and the host
@@ -71,25 +86,36 @@
*/
void executeTransition(Transition tranReq);
- /** @brief Callback function on system state changes
+ /** @brief Callback function on systemd state changes
*
- * Check if the state is relevant to the Host and if so, update
- * corresponding host object's state
+ * Will just do a call into the appropriate object for processing
*
- * @param[in] msg - Data associated with subscribed signal
- * @param[in] userData - Pointer to this object instance
- * @param[in] retError - Return error data
+ * @param[in] msg - Data associated with subscribed signal
+ * @param[in] userData - Pointer to this object instance
+ * @param[out] retError - Not used but required with signal API
*
*/
- static int handleSysStateChange(sd_bus_message* msg,
+ static int sysStateChangeSignal(sd_bus_message* msg,
void* userData,
sd_bus_error* retError);
+ /** @brief Check if systemd state change is relevant to this object
+ *
+ * Instance specific interface to handle the detected systemd state
+ * change
+ *
+ * @param[in] msg - Data associated with subscribed signal
+ * @param[out] retError - Not used but required with signal API
+ *
+ */
+ int sysStateChange(sd_bus_message* msg,
+ sd_bus_error* retError);
+
/** @brief Persistent sdbusplus DBus bus connection. */
sdbusplus::bus::bus& bus;
- /** @brief Used to subscribe to dbus system state changes */
- sdbusplus::server::match::match stateSignal;
+ /** @brief Used to subscribe to dbus systemd signals **/
+ sdbusplus::server::match::match systemdSignals;
};
} // namespace manager