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/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);
}
});
}