Call systemd SetTime directly
Internally inside phosphor-time-manager, the elapsed(uint64) dbus call
just forwards the request directly to systemd after static casting to
int64_t (signed).
bmcweb should just call systemd directly, for several reasons.
phosphor-timesyncd might block on other calls, given it's a single
threaded blocking design, due to bugs like #264. Calling systemd
directly means that calls that don't require phosphor networkd won't be
blocked.
Calling systemd directly allows bmcweb to drop some code that parses a
date as int64_t, then converts it to uint64_t to fulfill the phosphor
datetime interface. We can now keep int64_t all the way through.
Calling systemd directly allows bmcweb to give a more specific error
code in the case there NTP is enabled, registering a
PropertyValueConflict error, instead of a 500 InternalError.
Tested:
Patching DateTime property with NTP enabled returns 400,
PropertyValueConflict
```
curl -vvvv -k --user "root:0penBmc" -H "Content-Type: application/json" -X PATCH -d '{"DateTime":"2020-12-15T15:40:52+00:00"}' https://192.168.7.2/redfish/v1/Managers/bmc
```
Disabling NTP using the following command:
```
curl -vvvv -k --user "root:0penBmc" -H "Content-Type: application/json" -X PATCH -d '{"NTP":{"ProtocolEnabled":false}}' https://192.168.7.2/redfish/v1/Managers/bmc/NetworkProtocol
```
Allows the prior command to succeed.
[1] https://github.com/openbmc/phosphor-time-manager/blob/5ce9ac0e56440312997b25771507585905e8b360/bmc_epoch.cpp#L126
Change-Id: I6fbb6f63e17de8ab847ca5ed4eadc2bd313586d2
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp
index ee7dd4a..30011e3 100644
--- a/redfish-core/include/utils/time_utils.hpp
+++ b/redfish-core/include/utils/time_utils.hpp
@@ -417,7 +417,7 @@
return std::make_pair(dateTime, timeOffset);
}
-using usSinceEpoch = std::chrono::duration<uint64_t, std::micro>;
+using usSinceEpoch = std::chrono::duration<int64_t, std::micro>;
std::optional<usSinceEpoch> dateStringToEpoch(std::string_view datetime);
} // namespace time_utils
} // namespace redfish
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index 527076f..26abec0 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -1857,8 +1857,37 @@
});
}
-inline void setDateTime(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
- std::string datetime)
+inline void
+ afterSetDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const boost::system::error_code& ec,
+ const sdbusplus::message_t& msg)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
+ ec);
+ const sd_bus_error* dbusError = msg.get_error();
+ if (dbusError != nullptr)
+ {
+ std::string_view errorName(dbusError->name);
+ if (errorName ==
+ "org.freedesktop.timedate1.AutomaticTimeSyncEnabled")
+ {
+ BMCWEB_LOG_DEBUG("Setting conflict");
+ messages::propertyValueConflict(
+ asyncResp->res, "DateTime",
+ "Managers/NetworkProtocol/NTPProcotolEnabled");
+ return;
+ }
+ }
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ asyncResp->res.result(boost::beast::http::status::no_content);
+}
+
+inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& datetime)
{
BMCWEB_LOG_DEBUG("Set date time: {}", datetime);
@@ -1870,22 +1899,17 @@
"DateTime");
return;
}
- sdbusplus::asio::setProperty(
- *crow::connections::systemBus, "xyz.openbmc_project.Time.Manager",
- "/xyz/openbmc_project/time/bmc", "xyz.openbmc_project.Time.EpochTime",
- "Elapsed", us->count(),
- [asyncResp{std::move(asyncResp)},
- datetime{std::move(datetime)}](const boost::system::error_code& ec) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG("Failed to set elapsed time. "
- "DBUS response error {}",
- ec);
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue["DateTime"] = datetime;
- });
+ // Set the absolute datetime
+ bool relative = false;
+ bool interactive = false;
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code& ec,
+ const sdbusplus::message_t& msg) {
+ afterSetDateTime(asyncResp, ec, msg);
+ },
+ "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
+ "org.freedesktop.timedate1", "SetTime", us->count(), relative,
+ interactive);
}
inline void
@@ -2259,7 +2283,7 @@
}
if (datetime)
{
- setDateTime(asyncResp, std::move(*datetime));
+ setDateTime(asyncResp, *datetime);
}
});
}
diff --git a/redfish-core/src/utils/time_utils.cpp b/redfish-core/src/utils/time_utils.cpp
index f427ba6..3aa3e79 100644
--- a/redfish-core/src/utils/time_utils.cpp
+++ b/redfish-core/src/utils/time_utils.cpp
@@ -12,13 +12,13 @@
namespace redfish::time_utils
{
-using usSinceEpoch = std::chrono::duration<uint64_t, std::micro>;
+
std::optional<usSinceEpoch> dateStringToEpoch(std::string_view datetime)
{
for (const char* format : std::to_array({"%FT%T%Ez", "%FT%TZ", "%FT%T"}))
{
// Parse using signed so we can detect negative dates
- std::chrono::sys_time<std::chrono::duration<int64_t, std::micro>> date;
+ std::chrono::sys_time<usSinceEpoch> date;
std::istringstream iss(std::string{datetime});
#if __cpp_lib_chrono >= 201907L
namespace chrono_from_stream = std::chrono;
@@ -36,7 +36,7 @@
// More information left at end of string.
continue;
}
- return usSinceEpoch{date.time_since_epoch().count()};
+ return date.time_since_epoch();
}
}
return std::nullopt;