blob: d678ab47a94019ac38790d8d1e0b69ca14e61a91 [file] [log] [blame]
Iftekharul Islamcd789502017-04-19 14:37:55 -05001/**
2 * Controller for date-time
3 *
4 * @module app/configuration
5 * @exports dateTimeController
6 * @name dateTimeController
Iftekharul Islamcd789502017-04-19 14:37:55 -05007 */
8
Andrew Geisslerba5e3f32018-05-24 10:58:00 -07009window.angular && (function(angular) {
10 'use strict';
Iftekharul Islamcd789502017-04-19 14:37:55 -050011
Andrew Geisslerd27bb132018-05-24 11:07:27 -070012 angular.module('app.configuration').controller('dateTimeController', [
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -050013 '$scope', 'APIUtils', '$route', '$q', 'toastService', '$timeout',
14 function($scope, APIUtils, $route, $q, toastService, $timeout) {
Gunnar Millsb7ea2792018-07-18 13:01:48 -050015 $scope.bmc = {};
Gunnar Millseab32132018-09-27 10:07:17 -050016 // Only used when the owner is "Split"
Gunnar Millsb7ea2792018-07-18 13:01:48 -050017 $scope.host = {};
18 $scope.ntp = {servers: []};
Gunnar Mills2f955bd2018-10-13 16:56:10 -050019 $scope.time = {mode: '', owner: ''};
20 // Possible time owners
21 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/xyz/openbmc_project/Time/Owner.interface.yaml#L13
22 $scope.timeOwners = ['BMC', 'Host', 'Both', 'Split'];
Gunnar Mills7de38662018-07-18 13:01:48 -050023 $scope.loading = true;
Gunnar Mills2f955bd2018-10-13 16:56:10 -050024 var timePath = '/xyz/openbmc_project/time/';
Gunnar Mills7de38662018-07-18 13:01:48 -050025
Gunnar Millsc74d4342018-07-18 14:52:02 -050026 var getTimePromise = APIUtils.getTime().then(
Gunnar Mills7de38662018-07-18 13:01:48 -050027 function(data) {
Gunnar Millsb7ea2792018-07-18 13:01:48 -050028 // The time is returned as Epoch microseconds convert to
29 // milliseconds.
Gunnar Mills2f955bd2018-10-13 16:56:10 -050030 if (data.data[timePath + 'bmc'] &&
31 data.data[timePath + 'bmc'].hasOwnProperty('Elapsed')) {
Gunnar Millsb7ea2792018-07-18 13:01:48 -050032 $scope.bmc.date =
Gunnar Mills2f955bd2018-10-13 16:56:10 -050033 new Date(data.data[timePath + 'bmc'].Elapsed / 1000);
Gunnar Millsb7ea2792018-07-18 13:01:48 -050034 // Don't care about milliseconds and don't want them displayed
35 $scope.bmc.date.setMilliseconds(0);
Alexander Filippovdbf04812018-11-16 16:26:04 +030036
37 // Examples:
38 // Central Standard Time (UTC-06:00)
39 // Moscow Standard Time (UTC+03:00)
40 $scope.bmc.timezone = getUserTimezone($scope.bmc.date) + ' ' +
41 createOffset($scope.bmc.date);
Gunnar Millsb7ea2792018-07-18 13:01:48 -050042 }
Gunnar Mills2f955bd2018-10-13 16:56:10 -050043 if (data.data[timePath + 'host'] &&
44 data.data[timePath + 'host'].hasOwnProperty('Elapsed')) {
Gunnar Millsb7ea2792018-07-18 13:01:48 -050045 $scope.host.date =
Gunnar Mills2f955bd2018-10-13 16:56:10 -050046 new Date(data.data[timePath + 'host'].Elapsed / 1000);
Gunnar Millsb7ea2792018-07-18 13:01:48 -050047 $scope.host.date.setMilliseconds(0);
Alexander Filippovdbf04812018-11-16 16:26:04 +030048 $scope.host.timezone = getUserTimezone($scope.bmc.date) + ' ' +
49 createOffset($scope.bmc.date);
Gunnar Millsb7ea2792018-07-18 13:01:48 -050050 }
Gunnar Mills2f955bd2018-10-13 16:56:10 -050051 if (data.data[timePath + 'owner'] &&
52 data.data[timePath + 'owner'].hasOwnProperty('TimeOwner')) {
53 $scope.time.owner =
54 data.data[timePath + 'owner'].TimeOwner.split('.').pop();
Gunnar Millsb7ea2792018-07-18 13:01:48 -050055 }
Gunnar Mills2f955bd2018-10-13 16:56:10 -050056 if (data.data[timePath + 'sync_method'] &&
57 data.data[timePath + 'sync_method'].hasOwnProperty(
Gunnar Millsb7ea2792018-07-18 13:01:48 -050058 'TimeSyncMethod')) {
Gunnar Mills2f955bd2018-10-13 16:56:10 -050059 $scope.time.mode = data.data[timePath + 'sync_method']
Gunnar Millsb7ea2792018-07-18 13:01:48 -050060 .TimeSyncMethod.split('.')
61 .pop();
62 }
Gunnar Mills7de38662018-07-18 13:01:48 -050063 },
64 function(error) {
65 console.log(JSON.stringify(error));
66 });
67
Gunnar Millsb7ea2792018-07-18 13:01:48 -050068 var getNTPPromise = APIUtils.getNTPServers().then(
69 function(data) {
70 $scope.ntp.servers = data.data;
71 },
72 function(error) {
73 console.log(JSON.stringify(error));
74 });
75
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -050076 var promises = [getTimePromise, getNTPPromise];
Gunnar Millsb7ea2792018-07-18 13:01:48 -050077
78 $q.all(promises).finally(function() {
Gunnar Mills7de38662018-07-18 13:01:48 -050079 $scope.loading = false;
80 });
Gunnar Millsb7ea2792018-07-18 13:01:48 -050081
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -050082 /**
83 * https://github.com/openbmc/phosphor-time-manager/blob/master/README.md#special-note-on-changing-ntp-setting
84 * When time mode is initially set to Manual from NTP,
85 * NTP service is disabled and the NTP service is
86 * stopping but not stopped, setting time will return an error.
87 * There are no responses from backend to notify when NTP is stopped.
88 * To work around, a timeout is set to allow NTP to fully stop
89 * TODO: remove timeout if backend solves
90 * https://github.com/openbmc/openbmc/issues/3459
91 */
92 $scope.saveDateTimeSettings = function() {
Gunnar Millsb7ea2792018-07-18 13:01:48 -050093 $scope.loading = true;
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -050094 if ($scope.time.mode == 'Manual' || $scope.time.owner == 'Split') {
95 setTimeMode()
96 .then(setTimeOwner)
97 .then(setNTPServers)
98 .then($timeout(setDateTime, 20000));
99 } else {
100 setTimeMode()
101 .then(setTimeOwner)
102 .then(setNTPServers)
103 .then(
104 function() {
105 toastService.success('Date and time settings saved');
106 },
107 function(errors) {
108 console.log(JSON.stringify(errors));
109 toastService.error(
110 'Date and time settings could not be saved');
111 })
112 .finally(function() {
113 $scope.loading = false;
114 });
115 }
116 };
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500117
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -0500118 const setDateTime = function() {
119 var manualPromises = [];
120 if ($scope.time.mode == 'Manual') {
121 // If owner is 'Split' set both.
122 // If owner is 'Host' set only it.
123 if ($scope.time.owner != 'Host') {
124 manualPromises.push(setBMCTime($scope.bmc.date.getTime() * 1000));
125 }
126 // Even though we are setting Host time, we are setting from
127 // the BMC date and time fields labeled "BMC and Host Time"
128 // currently.
129 if ($scope.time.owner == 'Host') {
130 manualPromises.push(setHostTime($scope.bmc.date.getTime() * 1000));
131 }
132 }
133 // Set the Host if Split even if NTP. In split mode, the host has
134 // its own date and time field set from it.
135 if ($scope.time.owner == 'Split') {
136 manualPromises.push(setHostTime($scope.host.date.getTime() * 1000));
137 }
Gunnar Millsf378c772018-09-27 08:53:07 -0500138
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -0500139 $q.all(manualPromises)
140 .then(
141 function() {
142 toastService.success('Date and time settings saved');
143 },
144 function(errors) {
145 console.log(JSON.stringify(errors));
146 toastService.error(
147 'Date and time settings could not be saved');
148 })
149 .finally(function() {
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500150 $scope.loading = false;
151 });
152 };
Dixsie Wolmersfdcb35e2019-09-26 14:00:04 -0500153
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500154 $scope.refresh = function() {
155 $route.reload();
156 };
157
158 $scope.addNTPField = function() {
159 $scope.ntp.servers.push('');
160 };
161
Gunnar Mills90121f32018-09-16 21:22:45 -0500162 $scope.removeNTPField = function(index) {
163 $scope.ntp.servers.splice(index, 1);
164 };
165
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500166 function setNTPServers() {
167 // Remove any empty strings from the array. Important because we add an
168 // empty string to the end so the user can add a new NTP server, if the
169 // user doesn't fill out the field, we don't want to add.
170 $scope.ntp.servers = $scope.ntp.servers.filter(Boolean);
171 // NTP servers does not allow an empty array, since we remove all empty
172 // strings above, could have an empty array. TODO: openbmc/openbmc#3240
173 if ($scope.ntp.servers.length == 0) {
174 $scope.ntp.servers.push('');
175 }
176 return APIUtils.setNTPServers($scope.ntp.servers);
177 }
178
179 function setTimeMode() {
180 return APIUtils.setTimeMode(
181 'xyz.openbmc_project.Time.Synchronization.Method.' +
Gunnar Mills2f955bd2018-10-13 16:56:10 -0500182 $scope.time.mode);
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500183 }
184
185 function setTimeOwner() {
186 return APIUtils.setTimeOwner(
Gunnar Mills2f955bd2018-10-13 16:56:10 -0500187 'xyz.openbmc_project.Time.Owner.Owners.' + $scope.time.owner);
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500188 }
189
Gunnar Millseab32132018-09-27 10:07:17 -0500190 function setBMCTime(time) {
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500191 // Add the separate date and time objects and convert to Epoch time in
192 // microseconds.
Gunnar Millseab32132018-09-27 10:07:17 -0500193 return APIUtils.setBMCTime(time);
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500194 }
195
Gunnar Millseab32132018-09-27 10:07:17 -0500196 function setHostTime(time) {
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500197 // Add the separate date and time objects and convert to Epoch time
198 // microseconds.
Gunnar Millseab32132018-09-27 10:07:17 -0500199 return APIUtils.setHostTime(time);
Gunnar Millsb7ea2792018-07-18 13:01:48 -0500200 }
beccabroek569ccf62018-10-29 13:46:53 -0500201 function createOffset(date) {
202 // https://stackoverflow.com/questions/9149556/how-to-get-utc-offset-in-javascript-analog-of-timezoneinfo-getutcoffset-in-c
203 var sign = (date.getTimezoneOffset() > 0) ? '-' : '+';
204 var offset = Math.abs(date.getTimezoneOffset());
205 var hours = pad(Math.floor(offset / 60));
206 var minutes = pad(offset % 60);
207 return '(UTC' + sign + hours + ':' + minutes + ')';
208 }
Alexander Filippovdbf04812018-11-16 16:26:04 +0300209 function getUserTimezone(date) {
210 const ro = Intl.DateTimeFormat().resolvedOptions();
211 // A safe, easy way to get the timezone (e.g. Central Standard Time) is
212 // to subtract the time string without a timezone from the time string
213 // with a timezone.
214 // Hardcoded to 'en-US' so all timezones are displayed in English
215 // (e.g. Moscow Standard Time).
216 var ret = date.toLocaleTimeString('en-US', {timeZoneName: 'long'})
217 .replace(date.toLocaleTimeString('en-US'), '')
218 .trim();
219 // Do not return GMT+/-offset.
220 if (ret.indexOf('GMT') >= 0) {
221 return '';
222 }
223 return ret;
224 }
beccabroek569ccf62018-10-29 13:46:53 -0500225 function pad(value) {
226 return value < 10 ? '0' + value : value;
227 }
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700228 }
229 ]);
Iftekharul Islamcd789502017-04-19 14:37:55 -0500230})(angular);