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/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