blob: 92864db69f0cf89338a5e303988b6d40318d8422 [file] [log] [blame]
/**
* 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);