xref: /openbmc/phosphor-webui/app/configuration/controllers/date-time-controller.js (revision 569ccf66e58aacd50eaf53518c50c0ad4d448333)
1 /**
2  * Controller for date-time
3  *
4  * @module app/configuration
5  * @exports dateTimeController
6  * @name dateTimeController
7  */
8 
9 window.angular && (function(angular) {
10   'use strict';
11 
12   angular.module('app.configuration').controller('dateTimeController', [
13     '$scope', '$window', 'APIUtils', '$route', '$q',
14     function($scope, $window, APIUtils, $route, $q) {
15       $scope.bmc = {};
16       // Only used when the owner is "Split"
17       $scope.host = {};
18       $scope.ntp = {servers: []};
19       $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'];
23       $scope.error = false;
24       $scope.success = false;
25       $scope.loading = true;
26       var timePath = '/xyz/openbmc_project/time/';
27 
28       var getTimePromise = APIUtils.getTime().then(
29           function(data) {
30             // The time is returned as Epoch microseconds convert to
31             // milliseconds.
32             if (data.data[timePath + 'bmc'] &&
33                 data.data[timePath + 'bmc'].hasOwnProperty('Elapsed')) {
34               $scope.bmc.date =
35                   new Date(data.data[timePath + 'bmc'].Elapsed / 1000);
36               // Don't care about milliseconds and don't want them displayed
37               $scope.bmc.date.setMilliseconds(0);
38               // https://stackoverflow.com/questions/1091372/getting-the-clients-timezone-in-javascript
39               // EDT (UTC - 04:00)
40               $scope.bmc.timezone =
41                   $scope.bmc.date.toString().match(/\(([A-Za-z\s].*)\)/)[1] +
42                   ' ' + createOffset($scope.bmc.date);
43             }
44             if (data.data[timePath + 'host'] &&
45                 data.data[timePath + 'host'].hasOwnProperty('Elapsed')) {
46               $scope.host.date =
47                   new Date(data.data[timePath + 'host'].Elapsed / 1000);
48               $scope.host.date.setMilliseconds(0);
49               $scope.host.timezone =
50                   $scope.host.date.toString().match(/([A-Z]+[\+-][0-9]+.*)/)[1];
51             }
52             if (data.data[timePath + 'owner'] &&
53                 data.data[timePath + 'owner'].hasOwnProperty('TimeOwner')) {
54               $scope.time.owner =
55                   data.data[timePath + 'owner'].TimeOwner.split('.').pop();
56             }
57             if (data.data[timePath + 'sync_method'] &&
58                 data.data[timePath + 'sync_method'].hasOwnProperty(
59                     'TimeSyncMethod')) {
60               $scope.time.mode = data.data[timePath + 'sync_method']
61                                      .TimeSyncMethod.split('.')
62                                      .pop();
63             }
64           },
65           function(error) {
66             console.log(JSON.stringify(error));
67           });
68 
69       var getNTPPromise = APIUtils.getNTPServers().then(
70           function(data) {
71             $scope.ntp.servers = data.data;
72           },
73           function(error) {
74             console.log(JSON.stringify(error));
75           });
76 
77       var promises = [
78         getTimePromise,
79         getNTPPromise,
80       ];
81 
82       $q.all(promises).finally(function() {
83         $scope.loading = false;
84       });
85 
86       $scope.setTime = function() {
87         $scope.error = false;
88         $scope.success = false;
89         $scope.loading = true;
90         var promises = [setTimeMode(), setTimeOwner(), setNTPServers()];
91 
92         $q.all(promises).then(
93             function() {
94               // Have to set the time mode and time owner first to avoid a
95               // insufficient permissions if the time mode or time owner had
96               // changed.
97               var manual_promises = [];
98               if ($scope.time.mode == 'Manual') {
99                 // If owner is 'Split' set both.
100                 // If owner is 'Host' set only it.
101                 // Else set BMC only. See:
102                 // https://github.com/openbmc/phosphor-time-manager/blob/master/README.md
103                 if ($scope.time.owner != 'Host') {
104                   manual_promises.push(
105                       setBMCTime($scope.bmc.date.getTime() * 1000));
106                 }
107                 // Even though we are setting Host time, we are setting from
108                 // the BMC date and time fields labeled "BMC and Host Time"
109                 // currently.
110                 if ($scope.time.owner == 'Host') {
111                   manual_promises.push(
112                       setHostTime($scope.bmc.date.getTime() * 1000));
113                 }
114               }
115               // Set the Host if Split even if NTP. In split mode, the host has
116               // its own date and time field. Set from it.
117               if ($scope.time.owner == 'Split') {
118                 manual_promises.push(
119                     setHostTime($scope.host.date.getTime() * 1000));
120               }
121 
122               $q.all(manual_promises)
123                   .then(
124                       function() {
125                         $scope.success = true;
126                       },
127                       function(errors) {
128                         console.log(JSON.stringify(errors));
129                         $scope.error = true;
130                       })
131                   .finally(function() {
132                     $scope.loading = false;
133                   });
134             },
135             function(errors) {
136               console.log(JSON.stringify(errors));
137               $scope.error = true;
138               $scope.loading = false;
139             });
140       };
141       $scope.refresh = function() {
142         $route.reload();
143       };
144 
145       $scope.addNTPField = function() {
146         $scope.ntp.servers.push('');
147       };
148 
149       $scope.removeNTPField = function(index) {
150         $scope.ntp.servers.splice(index, 1);
151       };
152 
153       function setNTPServers() {
154         // Remove any empty strings from the array. Important because we add an
155         // empty string to the end so the user can add a new NTP server, if the
156         // user doesn't fill out the field, we don't want to add.
157         $scope.ntp.servers = $scope.ntp.servers.filter(Boolean);
158         // NTP servers does not allow an empty array, since we remove all empty
159         // strings above, could have an empty array. TODO: openbmc/openbmc#3240
160         if ($scope.ntp.servers.length == 0) {
161           $scope.ntp.servers.push('');
162         }
163         return APIUtils.setNTPServers($scope.ntp.servers);
164       }
165 
166       function setTimeMode() {
167         return APIUtils.setTimeMode(
168             'xyz.openbmc_project.Time.Synchronization.Method.' +
169             $scope.time.mode);
170       }
171 
172       function setTimeOwner() {
173         return APIUtils.setTimeOwner(
174             'xyz.openbmc_project.Time.Owner.Owners.' + $scope.time.owner);
175       }
176 
177       function setBMCTime(time) {
178         // Add the separate date and time objects and convert to Epoch time in
179         // microseconds.
180         return APIUtils.setBMCTime(time);
181       }
182 
183       function setHostTime(time) {
184         // Add the separate date and time objects and convert to Epoch time
185         // microseconds.
186         return APIUtils.setHostTime(time);
187       }
188       function createOffset(date) {
189         // https://stackoverflow.com/questions/9149556/how-to-get-utc-offset-in-javascript-analog-of-timezoneinfo-getutcoffset-in-c
190         var sign = (date.getTimezoneOffset() > 0) ? '-' : '+';
191         var offset = Math.abs(date.getTimezoneOffset());
192         var hours = pad(Math.floor(offset / 60));
193         var minutes = pad(offset % 60);
194         return '(UTC' + sign + hours + ':' + minutes + ')';
195       }
196       function pad(value) {
197         return value < 10 ? '0' + value : value;
198       }
199     }
200   ]);
201 })(angular);
202