1/**
2 * Controller for date-time
3 *
4 * @module app/configuration
5 * @exports dateTimeController
6 * @name dateTimeController
7 */
8
9window.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              // GMT-0400 (EDT)
40              $scope.bmc.timezone =
41                  $scope.bmc.date.toString().match(/([A-Z]+[\+-][0-9]+.*)/)[1];
42            }
43            if (data.data[timePath + 'host'] &&
44                data.data[timePath + 'host'].hasOwnProperty('Elapsed')) {
45              $scope.host.date =
46                  new Date(data.data[timePath + 'host'].Elapsed / 1000);
47              $scope.host.date.setMilliseconds(0);
48              $scope.host.timezone =
49                  $scope.host.date.toString().match(/([A-Z]+[\+-][0-9]+.*)/)[1];
50            }
51            if (data.data[timePath + 'owner'] &&
52                data.data[timePath + 'owner'].hasOwnProperty('TimeOwner')) {
53              $scope.time.owner =
54                  data.data[timePath + 'owner'].TimeOwner.split('.').pop();
55            }
56            if (data.data[timePath + 'sync_method'] &&
57                data.data[timePath + 'sync_method'].hasOwnProperty(
58                    'TimeSyncMethod')) {
59              $scope.time.mode = data.data[timePath + 'sync_method']
60                                     .TimeSyncMethod.split('.')
61                                     .pop();
62            }
63          },
64          function(error) {
65            console.log(JSON.stringify(error));
66          });
67
68      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
76      var promises = [
77        getTimePromise,
78        getNTPPromise,
79      ];
80
81      $q.all(promises).finally(function() {
82        $scope.loading = false;
83      });
84
85      $scope.setTime = function() {
86        $scope.error = false;
87        $scope.success = false;
88        $scope.loading = true;
89        var promises = [setTimeMode(), setTimeOwner(), setNTPServers()];
90
91        $q.all(promises).then(
92            function() {
93              // Have to set the time mode and time owner first to avoid a
94              // insufficient permissions if the time mode or time owner had
95              // changed.
96              var manual_promises = [];
97              if ($scope.time.mode == 'Manual') {
98                // If owner is 'Split' set both.
99                // If owner is 'Host' set only it.
100                // Else set BMC only. See:
101                // https://github.com/openbmc/phosphor-time-manager/blob/master/README.md
102                if ($scope.time.owner != 'Host') {
103                  manual_promises.push(
104                      setBMCTime($scope.bmc.date.getTime() * 1000));
105                }
106                // Even though we are setting Host time, we are setting from
107                // the BMC date and time fields labeled "BMC and Host Time"
108                // currently.
109                if ($scope.time.owner == 'Host') {
110                  manual_promises.push(
111                      setHostTime($scope.bmc.date.getTime() * 1000));
112                }
113              }
114              // Set the Host if Split even if NTP. In split mode, the host has
115              // its own date and time field. Set from it.
116              if ($scope.time.owner == 'Split') {
117                manual_promises.push(
118                    setHostTime($scope.host.date.getTime() * 1000));
119              }
120
121              $q.all(manual_promises)
122                  .then(
123                      function() {
124                        $scope.success = true;
125                      },
126                      function(errors) {
127                        console.log(JSON.stringify(errors));
128                        $scope.error = true;
129                      })
130                  .finally(function() {
131                    $scope.loading = false;
132                  });
133            },
134            function(errors) {
135              console.log(JSON.stringify(errors));
136              $scope.error = true;
137              $scope.loading = false;
138            });
139      };
140      $scope.refresh = function() {
141        $route.reload();
142      };
143
144      $scope.addNTPField = function() {
145        $scope.ntp.servers.push('');
146      };
147
148      $scope.removeNTPField = function(index) {
149        $scope.ntp.servers.splice(index, 1);
150      };
151
152      function setNTPServers() {
153        // Remove any empty strings from the array. Important because we add an
154        // empty string to the end so the user can add a new NTP server, if the
155        // user doesn't fill out the field, we don't want to add.
156        $scope.ntp.servers = $scope.ntp.servers.filter(Boolean);
157        // NTP servers does not allow an empty array, since we remove all empty
158        // strings above, could have an empty array. TODO: openbmc/openbmc#3240
159        if ($scope.ntp.servers.length == 0) {
160          $scope.ntp.servers.push('');
161        }
162        return APIUtils.setNTPServers($scope.ntp.servers);
163      }
164
165      function setTimeMode() {
166        return APIUtils.setTimeMode(
167            'xyz.openbmc_project.Time.Synchronization.Method.' +
168            $scope.time.mode);
169      }
170
171      function setTimeOwner() {
172        return APIUtils.setTimeOwner(
173            'xyz.openbmc_project.Time.Owner.Owners.' + $scope.time.owner);
174      }
175
176      function setBMCTime(time) {
177        // Add the separate date and time objects and convert to Epoch time in
178        // microseconds.
179        return APIUtils.setBMCTime(time);
180      }
181
182      function setHostTime(time) {
183        // Add the separate date and time objects and convert to Epoch time
184        // microseconds.
185        return APIUtils.setHostTime(time);
186      }
187    }
188  ]);
189})(angular);
190