| /** |
| * Controller for date-time |
| * |
| * @module app/configuration |
| * @exports dateTimeController |
| * @name dateTimeController |
| */ |
| |
| window.angular && (function(angular) { |
| 'use strict'; |
| |
| angular.module('app.configuration').controller('dateTimeController', [ |
| '$scope', 'APIUtils', '$route', '$q', 'toastService', '$timeout', |
| function($scope, APIUtils, $route, $q, toastService, $timeout) { |
| $scope.bmc = {}; |
| // Only used when the owner is "Split" |
| $scope.host = {}; |
| $scope.ntp = {servers: []}; |
| $scope.time = {mode: '', owner: ''}; |
| // Possible time owners |
| // https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/xyz/openbmc_project/Time/Owner.interface.yaml#L13 |
| $scope.timeOwners = ['BMC', 'Host', 'Both', 'Split']; |
| $scope.loading = true; |
| var timePath = '/xyz/openbmc_project/time/'; |
| |
| var getTimePromise = APIUtils.getTime().then( |
| function(data) { |
| // The time is returned as Epoch microseconds convert to |
| // milliseconds. |
| if (data.data[timePath + 'bmc'] && |
| data.data[timePath + 'bmc'].hasOwnProperty('Elapsed')) { |
| $scope.bmc.date = |
| new Date(data.data[timePath + 'bmc'].Elapsed / 1000); |
| // Don't care about milliseconds and don't want them displayed |
| $scope.bmc.date.setMilliseconds(0); |
| |
| // Examples: |
| // Central Standard Time (UTC-06:00) |
| // Moscow Standard Time (UTC+03:00) |
| $scope.bmc.timezone = getUserTimezone($scope.bmc.date) + ' ' + |
| createOffset($scope.bmc.date); |
| } |
| if (data.data[timePath + 'host'] && |
| data.data[timePath + 'host'].hasOwnProperty('Elapsed')) { |
| $scope.host.date = |
| new Date(data.data[timePath + 'host'].Elapsed / 1000); |
| $scope.host.date.setMilliseconds(0); |
| $scope.host.timezone = getUserTimezone($scope.bmc.date) + ' ' + |
| createOffset($scope.bmc.date); |
| } |
| if (data.data[timePath + 'owner'] && |
| data.data[timePath + 'owner'].hasOwnProperty('TimeOwner')) { |
| $scope.time.owner = |
| data.data[timePath + 'owner'].TimeOwner.split('.').pop(); |
| } |
| if (data.data[timePath + 'sync_method'] && |
| data.data[timePath + 'sync_method'].hasOwnProperty( |
| 'TimeSyncMethod')) { |
| $scope.time.mode = data.data[timePath + 'sync_method'] |
| .TimeSyncMethod.split('.') |
| .pop(); |
| } |
| }, |
| function(error) { |
| console.log(JSON.stringify(error)); |
| }); |
| |
| var getNTPPromise = APIUtils.getNTPServers().then( |
| function(data) { |
| $scope.ntp.servers = data.data; |
| }, |
| function(error) { |
| console.log(JSON.stringify(error)); |
| }); |
| |
| var promises = [getTimePromise, getNTPPromise]; |
| |
| $q.all(promises).finally(function() { |
| $scope.loading = false; |
| }); |
| |
| /** |
| * https://github.com/openbmc/phosphor-time-manager/blob/master/README.md#special-note-on-changing-ntp-setting |
| * When time mode is initially set to Manual from NTP, |
| * NTP service is disabled and the NTP service is |
| * stopping but not stopped, setting time will return an error. |
| * There are no responses from backend to notify when NTP is stopped. |
| * To work around, a timeout is set to allow NTP to fully stop |
| * TODO: remove timeout if backend solves |
| * https://github.com/openbmc/openbmc/issues/3459 |
| */ |
| $scope.saveDateTimeSettings = function() { |
| $scope.loading = true; |
| if ($scope.time.mode == 'Manual' || $scope.time.owner == 'Split') { |
| setTimeMode() |
| .then(setTimeOwner) |
| .then(setNTPServers) |
| .then($timeout(setDateTime, 20000)); |
| } else { |
| setTimeMode() |
| .then(setTimeOwner) |
| .then(setNTPServers) |
| .then( |
| function() { |
| toastService.success('Date and time settings saved'); |
| }, |
| function(errors) { |
| console.log(JSON.stringify(errors)); |
| toastService.error( |
| 'Date and time settings could not be saved'); |
| }) |
| .finally(function() { |
| $scope.loading = false; |
| }); |
| } |
| }; |
| |
| const setDateTime = function() { |
| var manualPromises = []; |
| if ($scope.time.mode == 'Manual') { |
| // If owner is 'Split' set both. |
| // If owner is 'Host' set only it. |
| if ($scope.time.owner != 'Host') { |
| manualPromises.push(setBMCTime($scope.bmc.date.getTime() * 1000)); |
| } |
| // Even though we are setting Host time, we are setting from |
| // the BMC date and time fields labeled "BMC and Host Time" |
| // currently. |
| if ($scope.time.owner == 'Host') { |
| manualPromises.push(setHostTime($scope.bmc.date.getTime() * 1000)); |
| } |
| } |
| // Set the Host if Split even if NTP. In split mode, the host has |
| // its own date and time field set from it. |
| if ($scope.time.owner == 'Split') { |
| manualPromises.push(setHostTime($scope.host.date.getTime() * 1000)); |
| } |
| |
| $q.all(manualPromises) |
| .then( |
| function() { |
| toastService.success('Date and time settings saved'); |
| }, |
| function(errors) { |
| console.log(JSON.stringify(errors)); |
| toastService.error( |
| 'Date and time settings could not be saved'); |
| }) |
| .finally(function() { |
| $scope.loading = false; |
| }); |
| }; |
| |
| $scope.refresh = function() { |
| $route.reload(); |
| }; |
| |
| $scope.addNTPField = function() { |
| $scope.ntp.servers.push(''); |
| }; |
| |
| $scope.removeNTPField = function(index) { |
| $scope.ntp.servers.splice(index, 1); |
| }; |
| |
| function setNTPServers() { |
| // Remove any empty strings from the array. If the |
| // user doesn't fill out the field, we don't want to add. |
| $scope.ntp.servers = $scope.ntp.servers.filter(Boolean); |
| |
| return APIUtils.setNTPServers($scope.ntp.servers); |
| } |
| |
| function setTimeMode() { |
| return APIUtils.setTimeMode( |
| 'xyz.openbmc_project.Time.Synchronization.Method.' + |
| $scope.time.mode); |
| } |
| |
| function setTimeOwner() { |
| return APIUtils.setTimeOwner( |
| 'xyz.openbmc_project.Time.Owner.Owners.' + $scope.time.owner); |
| } |
| |
| function setBMCTime(time) { |
| // Add the separate date and time objects and convert to Epoch time in |
| // microseconds. |
| return APIUtils.setBMCTime(time); |
| } |
| |
| function setHostTime(time) { |
| // Add the separate date and time objects and convert to Epoch time |
| // microseconds. |
| return APIUtils.setHostTime(time); |
| } |
| function createOffset(date) { |
| // https://stackoverflow.com/questions/9149556/how-to-get-utc-offset-in-javascript-analog-of-timezoneinfo-getutcoffset-in-c |
| var sign = (date.getTimezoneOffset() > 0) ? '-' : '+'; |
| var offset = Math.abs(date.getTimezoneOffset()); |
| var hours = pad(Math.floor(offset / 60)); |
| var minutes = pad(offset % 60); |
| return '(UTC' + sign + hours + ':' + minutes + ')'; |
| } |
| function getUserTimezone(date) { |
| const ro = Intl.DateTimeFormat().resolvedOptions(); |
| // A safe, easy way to get the timezone (e.g. Central Standard Time) is |
| // to subtract the time string without a timezone from the time string |
| // with a timezone. |
| // Hardcoded to 'en-US' so all timezones are displayed in English |
| // (e.g. Moscow Standard Time). |
| var ret = date.toLocaleTimeString('en-US', {timeZoneName: 'long'}) |
| .replace(date.toLocaleTimeString('en-US'), '') |
| .trim(); |
| // Do not return GMT+/-offset. |
| if (ret.indexOf('GMT') >= 0) { |
| return ''; |
| } |
| return ret; |
| } |
| function pad(value) { |
| return value < 10 ? '0' + value : value; |
| } |
| } |
| ]); |
| })(angular); |