sched-host-tran: store/restore the value of scheduled time and
requested transition
Store/restore the value of scheduled time and requested transition, in case
BMC is rebooted. After BMC is back, go on the host transition process based
on the stored values.
Tested:
1. Get current time
# date
Tue Mar 10 08:16:40 UTC 2020
2. Set scheduled time 08:25:00
# busctl set-property xyz.openbmc_project.State.ScheduledHostTransition \
/xyz/openbmc_project/state/host0 \
xyz.openbmc_project.State.ScheduledHostTransition ScheduledTime t 1583828700
3. Reboot BMC
4. Check sheduled time
# busctl get-property xyz.openbmc_project.State.ScheduledHostTransition \
/xyz/openbmc_project/state/host0 \
xyz.openbmc_project.State.ScheduledHostTransition ScheduledTime
t 1583828700
5. Do host transition after the scheduled time is reached.
6. Check the scheduled time again
# busctl get-property xyz.openbmc_project.State.ScheduledHostTransition \
/xyz/openbmc_project/state/host0 \
xyz.openbmc_project.State.ScheduledHostTransition ScheduledTime
t 0
Change-Id: I3bbae19a49e2fe84bf4e297e6daaa0461cbf2cb8
Signed-off-by: Carol Wang <wangkair@cn.ibm.com>
diff --git a/meson.build b/meson.build
index 790677d..fb24d76 100644
--- a/meson.build
+++ b/meson.build
@@ -32,6 +32,8 @@
conf.set_quoted(
'CHASSIS_STATE_CHANGE_PERSIST_PATH', get_option('chassis-state-change-persist-path'))
conf.set_quoted(
+ 'SCHEDULED_HOST_TRANSITION_PERSIST_PATH', get_option('scheduled-host-transition-persist-path'))
+conf.set_quoted(
'SCHEDULED_HOST_TRANSITION_BUSNAME', get_option('scheduled-host-transition-busname'))
conf.set(
'BOOT_COUNT_MAX_ALLOWED', get_option('boot-count-max-allowed'))
diff --git a/meson_options.txt b/meson_options.txt
index 443e85c..385323d 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -61,6 +61,12 @@
)
option(
+ 'scheduled-host-transition-persist-path', type: 'string',
+ value: '/var/lib/phosphor-state-manager/scheduledHostTransition',
+ description: 'Path of file for storing the scheduled time and the requested transition.',
+)
+
+option(
'boot-count-max-allowed', type: 'integer',
value: 3,
description: 'The maximum allowed reboot count.',
diff --git a/scheduled_host_transition.cpp b/scheduled_host_transition.cpp
index 9fdd32b..6ff28ac 100644
--- a/scheduled_host_transition.cpp
+++ b/scheduled_host_transition.cpp
@@ -4,7 +4,10 @@
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/ScheduledTime/error.hpp>
+#include <cereal/archives/json.hpp>
#include <chrono>
+#include <filesystem>
+#include <fstream>
#include <sys/timerfd.h>
#include <unistd.h>
@@ -24,6 +27,8 @@
namespace manager
{
+namespace fs = std::filesystem;
+
using namespace std::chrono;
using namespace phosphor::logging;
using namespace xyz::openbmc_project::ScheduledTime;
@@ -48,10 +53,9 @@
if (timer.isEnabled())
{
timer.setEnabled(false);
+ log<level::INFO>("scheduledTime: The function Scheduled Host "
+ "Transition is disabled.");
}
-
- log<level::INFO>("scheduledTime: The function Scheduled Host "
- "Transition is disabled.");
}
else
{
@@ -71,8 +75,12 @@
}
}
- // Set and return the scheduled time
- return HostTransition::scheduledTime(value);
+ // Set scheduledTime
+ HostTransition::scheduledTime(value);
+ // Store scheduled values
+ serializeScheduledValues();
+
+ return value;
}
seconds ScheduledHostTransition::getTime()
@@ -149,8 +157,9 @@
// Stop timer, since we need to do host transition once only
timer.setEnabled(false);
hostTransition();
- // Set scheduledTime to 0 to disable host transition
- HostTransition::scheduledTime(0);
+ // Set scheduledTime to 0 to disable host transition and update scheduled
+ // values
+ scheduledTime(0);
}
void ScheduledHostTransition::initialize()
@@ -209,12 +218,13 @@
void ScheduledHostTransition::handleTimeUpdates()
{
- if (!timer.isEnabled())
+ // Stop the timer if it's running.
+ // Don't return directly when timer is stopped, because the timer is always
+ // disabled after the BMC is rebooted.
+ if (timer.isEnabled())
{
- return;
+ timer.setEnabled(false);
}
- // Stop the timer if it's running
- timer.setEnabled(false);
// Get scheduled time
auto schedTime = HostTransition::scheduledTime();
@@ -229,11 +239,10 @@
auto deltaTime = seconds(schedTime) - getTime();
if (deltaTime <= seconds(0))
{
- // When BMC time is changed to be later than scheduled time, check the
- // state of host transition to decide whether need to do host transition
hostTransition();
- // Set scheduledTime to 0 to disable host transition
- HostTransition::scheduledTime(0);
+ // Set scheduledTime to 0 to disable host transition and update
+ // scheduled values
+ scheduledTime(0);
}
else
{
@@ -261,6 +270,60 @@
return 0;
}
+void ScheduledHostTransition::serializeScheduledValues()
+{
+ fs::path path{SCHEDULED_HOST_TRANSITION_PERSIST_PATH};
+ std::ofstream os(path.c_str(), std::ios::binary);
+ cereal::JSONOutputArchive oarchive(os);
+
+ oarchive(HostTransition::scheduledTime(),
+ HostTransition::scheduledTransition());
+}
+
+bool ScheduledHostTransition::deserializeScheduledValues(uint64_t& time,
+ Transition& trans)
+{
+ fs::path path{SCHEDULED_HOST_TRANSITION_PERSIST_PATH};
+
+ try
+ {
+ if (fs::exists(path))
+ {
+ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
+ cereal::JSONInputArchive iarchive(is);
+ iarchive(time, trans);
+ return true;
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>(e.what());
+ fs::remove(path);
+ }
+
+ return false;
+}
+
+void ScheduledHostTransition::restoreScheduledValues()
+{
+ uint64_t time;
+ Transition trans;
+ if (!deserializeScheduledValues(time, trans))
+ {
+ // set to default value
+ HostTransition::scheduledTime(0);
+ HostTransition::scheduledTransition(Transition::On);
+ }
+ else
+ {
+ HostTransition::scheduledTime(time);
+ HostTransition::scheduledTransition(trans);
+ // Rebooting BMC is something like the BMC time is changed,
+ // so go on with the same process as BMC time changed.
+ handleTimeUpdates();
+ }
+}
+
} // namespace manager
} // namespace state
} // namespace phosphor
diff --git a/scheduled_host_transition.hpp b/scheduled_host_transition.hpp
index a17ca3b..b42c5ae 100644
--- a/scheduled_host_transition.hpp
+++ b/scheduled_host_transition.hpp
@@ -31,11 +31,16 @@
public:
ScheduledHostTransition(sdbusplus::bus::bus& bus, const char* objPath,
const sdeventplus::Event& event) :
- ScheduledHostTransitionInherit(bus, objPath),
+ ScheduledHostTransitionInherit(bus, objPath, true),
bus(bus), event(event),
timer(event, std::bind(&ScheduledHostTransition::callback, this))
{
initialize();
+
+ restoreScheduledValues();
+
+ // We deferred this until we could get our property correct
+ this->emit_object_added();
}
~ScheduledHostTransition();
@@ -111,6 +116,22 @@
/** @brief Handle with the process when bmc time is changed*/
void handleTimeUpdates();
+
+ /** @brief Serialize the scheduled values */
+ void serializeScheduledValues();
+
+ /** @brief Deserialize the scheduled values
+ *
+ * @param[out] time - Deserialized scheduled time
+ * @param[out] trans - Deserialized requested transition
+ *
+ * @return bool - true if successful, false otherwise
+ */
+ bool deserializeScheduledValues(uint64_t& time, Transition& trans);
+
+ /** @brief Restore scheduled time and requested transition from persisted
+ * file */
+ void restoreScheduledValues();
};
} // namespace manager
} // namespace state
diff --git a/scheduled_host_transition_main.cpp b/scheduled_host_transition_main.cpp
index 4cd2436..61ab47a 100644
--- a/scheduled_host_transition_main.cpp
+++ b/scheduled_host_transition_main.cpp
@@ -1,11 +1,14 @@
#include <cstdlib>
#include <exception>
#include <sdbusplus/bus.hpp>
+#include <filesystem>
#include "config.h"
#include "scheduled_host_transition.hpp"
int main()
{
+ namespace fs = std::filesystem;
+
// Get a default event loop
auto event = sdeventplus::Event::get_default();
@@ -15,6 +18,13 @@
// For now, we only have one instance of the host
auto objPathInst = std::string{HOST_OBJPATH} + '0';
+ // Check SCHEDULED_HOST_TRANSITION_PERSIST_PATH
+ auto dir = fs::path(SCHEDULED_HOST_TRANSITION_PERSIST_PATH).parent_path();
+ if (!fs::exists(dir))
+ {
+ fs::create_directories(dir);
+ }
+
// Add sdbusplus ObjectManager.
sdbusplus::server::manager::manager objManager(bus, objPathInst.c_str());