PATCH support for DateTime
This commit adds PATCH support for the DateTime property.
To set the BMC time, it uses the
xyz.openbmc_project.Time.EpochTime.Elapsed property.
The BMC time can only be set if the BMC owns it's own time *and*
the time is not automatically synced with NTP server(s).
The input JSON for the PATCH request must speicfy datetime in
extended ISO 8601 format.
Tested:
=======
Precondition: Time owner should be BMC and sync method should be
Manual.
busctl get-property xyz.openbmc_project.Settings
/xyz/openbmc_project/time/owner
xyz.openbmc_project.Time.Owner TimeOwner
s "xyz.openbmc_project.Time.Owner.Owners.BMC"
busctl get-property xyz.openbmc_project.Settings
/xyz/openbmc_project/time/sync_method
xyz.openbmc_project.Time.Synchronization TimeSyncMethod
s "xyz.openbmc_project.Time.Synchronization.Method.Manual"
-- Setting date time:
curl -k -H "X-Auth-Token: $bmc_token" -X PATCH
https://${bmc}:${port}/redfish/v1/Managers/bmc -d
'{"DateTime": "2019-03-20T08:47:30.345+00:00"}'
{
"DateTime": "2019-03-20T08:47:30.345+00:00"
}
Invalid date time string:
curl -k -H "X-Auth-Token: $bmc_token" -X PATCH
https://${bmc}:${port}/redfish/v1/Managers/bmc -d
'{"DateTime": "2019-03-20T08:47:30.345+ds:00"}'
{
"DateTime@Message.ExtendedInfo": [
{
"@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
"Message": "The value 2019-03-20T08:47:30.345+ds:00 for the property
DateTime is of a different format than the property can accept.",
"MessageArgs": [
"2019-03-20T08:47:30.345+ds:00",
"DateTime"
],
"MessageId": "Base.1.4.0.PropertyValueFormatError",
"Resolution": "Correct the value for the property in the request body and
resubmit the request if the operation failed.",
"Severity": "Warning"
}
]
}
When the time sync method is NTP, the PATCH request fails as expected:
busctl get-property xyz.openbmc_project.Settings
/xyz/openbmc_project/time/sync_method
xyz.openbmc_project.Time.Synchronization TimeSyncMethod
s "xyz.openbmc_project.Time.Synchronization.Method.NTP"
curl -k -H "X-Auth-Token: $bmc_token" -X PATCH
https://${bmc}:${port}/redfish/v1/Managers/bmc -d '{"DateTime":
"2019-03-20T08:47:30+00:00"}'
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
"Message": "The request failed due to an internal service error. The
service is still operational.",
"MessageArgs": [],
"MessageId": "Base.1.4.0.InternalError",
"Resolution": "Resubmit the request. If the problem persists, consider
resetting the service.",
"Severity": "Critical"
}
],
"code": "Base.1.4.0.InternalError",
"message": "The request failed due to an internal service error. The
service is still operational."
}
}
When the time sync method is Manual, but the time owner is Host,
PATCH fails as expected again:
busctl get-property xyz.openbmc_project.Settings
/xyz/openbmc_project/time/owner
xyz.openbmc_project.Time.Owner TimeOwner
s "xyz.openbmc_project.Time.Owner.Owners.Host"
busctl get-property xyz.openbmc_project.Settings
/xyz/openbmc_project/time/sync_method
xyz.openbmc_project.Time.Synchronization TimeSyncMethod
s "xyz.openbmc_project.Time.Synchronization.Method.Manual"
curl -k -H "X-Auth-Token: $bmc_token" -X PATCH
https://${bmc}:${port}/redfish/v1/Managers/bmc -d '{"DateTime":
"2019-03-20T08:47:30+00:00"}'
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
"Message": "The request failed due to an internal service error. The
service is still operational.",
"MessageArgs": [],
"MessageId": "Base.1.4.0.InternalError",
"Resolution": "Resubmit the request. If the problem persists, consider
resetting the service.",
"Severity": "Critical"
}
],
"code": "Base.1.4.0.InternalError",
"message": "The request failed due to an internal service error. The
service is still operational."
}
}
Change-Id: Ie4a71e639b9a6577fae8627f0f69b6179506eb58
Signed-off-by: Santosh Puranik <santosh.puranik@in.ibm.com>
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index c73a218..a9efb4c 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -18,7 +18,9 @@
#include "node.hpp"
#include <boost/algorithm/string/replace.hpp>
+#include <boost/date_time.hpp>
#include <dbus_utility.hpp>
+#include <sstream>
#include <variant>
namespace redfish
@@ -1243,8 +1245,9 @@
const std::vector<std::string>& params) override
{
std::optional<nlohmann::json> oem;
+ std::optional<std::string> datetime;
- if (!json_util::readJson(req, res, "Oem", oem))
+ if (!json_util::readJson(req, res, "Oem", oem, "DateTime", datetime))
{
return;
}
@@ -1276,6 +1279,61 @@
}
}
}
+ if (datetime)
+ {
+ setDateTime(response, std::move(*datetime));
+ }
+ }
+
+ void setDateTime(std::shared_ptr<AsyncResp> aResp,
+ std::string datetime) const
+ {
+ BMCWEB_LOG_DEBUG << "Set date time: " << datetime;
+
+ std::stringstream stream(datetime);
+ // Convert from ISO 8601 to boost local_time
+ // (BMC only has time in UTC)
+ boost::posix_time::ptime posixTime;
+ boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
+ // Facet gets deleted with the stringsteam
+ auto ifc = std::make_unique<boost::local_time::local_time_input_facet>(
+ "%Y-%m-%d %H:%M:%S%F %ZP");
+ stream.imbue(std::locale(stream.getloc(), ifc.release()));
+
+ boost::local_time::local_date_time ldt(
+ boost::local_time::not_a_date_time);
+
+ if (stream >> ldt)
+ {
+ posixTime = ldt.utc_time();
+ boost::posix_time::time_duration dur = posixTime - epoch;
+ uint64_t durMicroSecs =
+ static_cast<uint64_t>(dur.total_microseconds());
+ crow::connections::systemBus->async_method_call(
+ [aResp{std::move(aResp)}, 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(aResp->res);
+ return;
+ }
+ aResp->res.jsonValue["DateTime"] = datetime;
+ },
+ "xyz.openbmc_project.Time.Manager",
+ "/xyz/openbmc_project/time/bmc",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Time.EpochTime", "Elapsed",
+ std::variant<uint64_t>(durMicroSecs));
+ }
+ else
+ {
+ messages::propertyValueFormatError(aResp->res, datetime,
+ "DateTime");
+ return;
+ }
}
std::string uuid;