1/**
2 * Controller for network
3 *
4 * @module app/configuration
5 * @exports networkController
6 * @name networkController
7 */
8
9window.angular && (function(angular) {
10  'use strict';
11
12  angular.module('app.configuration').directive('setFocusDnsField', function() {
13    return function(scope, element, attrs) {
14      var elem = window.document.getElementById(element[0].id);
15      // Focus on the newly created DNS server field
16      // Since this directive is also called when initializing DNS server fields
17      // on a page load, need to determine if the call is from a page load or
18      // from the user pressing the "Add new DNS server" button. The easiest way
19      // to do this is to check if the field is empty, if it is we know
20      // this is a new field since all empty fields are removed from the array.
21      if (!scope[attrs.ngModel] && elem) {
22        elem.focus();
23      }
24    };
25  });
26
27  angular.module('app.configuration').controller('networkController', [
28    '$scope', '$window', 'APIUtils', 'dataService', '$timeout', '$route', '$q',
29    function($scope, $window, APIUtils, dataService, $timeout, $route, $q) {
30      $scope.dataService = dataService;
31      $scope.network = {};
32      $scope.old_interface = {};
33      $scope.interface = {};
34      $scope.networkDevice = false;
35      $scope.hostname = '';
36      $scope.defaultgateway = '';
37      $scope.set_network_error = '';
38      $scope.set_network_success = false;
39      $scope.selectedInterface = '';
40      $scope.confirm_settings = false;
41      $scope.loading = false;
42
43      loadNetworkInfo();
44
45      $scope.selectInterface = function(interfaceId) {
46        $scope.interface = $scope.network.interfaces[interfaceId];
47        // Copy the interface so we know later if changes were made to the page
48        $scope.old_interface = JSON.parse(JSON.stringify($scope.interface));
49        $scope.selectedInterface = interfaceId;
50        $scope.networkDevice = false;
51      };
52
53      $scope.addDNSField = function() {
54        $scope.interface.Nameservers.push('');
55      };
56
57      $scope.setNetworkSettings = function() {
58        // Hides the confirm network settings modal
59        $scope.confirm_settings = false;
60        $scope.set_network_error = '';
61        $scope.set_network_success = false;
62        $scope.loading = true;
63        var promises = [];
64
65        // MAC Address are case-insensitive
66        if ($scope.interface.MACAddress.toLowerCase() !=
67            dataService.mac_address.toLowerCase()) {
68          promises.push(setMACAddress());
69        }
70        if ($scope.defaultgateway != dataService.defaultgateway) {
71          promises.push(setDefaultGateway());
72        }
73        if ($scope.hostname != dataService.hostname) {
74          promises.push(setHostname());
75        }
76        if ($scope.interface.DHCPEnabled != $scope.old_interface.DHCPEnabled) {
77          promises.push(setDHCPEnabled());
78        }
79
80        // Remove any empty strings from the array. Important because we add an
81        // empty string to the end so the user can add a new DNS server, if the
82        // user doesn't fill out the field, we don't want to add.
83        $scope.interface.Nameservers =
84            $scope.interface.Nameservers.filter(Boolean);
85        // toString() is a cheap way to compare 2 string arrays
86        if ($scope.interface.Nameservers.toString() !=
87            $scope.old_interface.Nameservers.toString()) {
88          promises.push(setNameservers());
89        }
90
91        // Set IPV4 IP Addresses, Netmask Prefix Lengths, and Gateways
92        if (!$scope.interface.DHCPEnabled) {
93          for (var i in $scope.interface.ipv4.values) {
94            if (!APIUtils.validIPV4IP(
95                    $scope.interface.ipv4.values[i].Address)) {
96              $scope.set_network_error =
97                  $scope.interface.ipv4.values[i].Address +
98                  ' invalid IP parameter';
99              $scope.loading = false;
100              return;
101            }
102            if (!APIUtils.validIPV4IP(
103                    $scope.interface.ipv4.values[i].Gateway)) {
104              $scope.set_network_error =
105                  $scope.interface.ipv4.values[i].Address +
106                  ' invalid gateway parameter';
107              $scope.loading = false;
108              return;
109            }
110            // The netmask prefix length will be undefined if outside range
111            if (!$scope.interface.ipv4.values[i].PrefixLength) {
112              $scope.set_network_error =
113                  $scope.interface.ipv4.values[i].Address +
114                  ' invalid Prefix Length parameter';
115              $scope.loading = false;
116              return;
117            }
118            if ($scope.interface.ipv4.values[i].Address !=
119                    $scope.old_interface.ipv4.values[i].Address ||
120                $scope.interface.ipv4.values[i].PrefixLength !=
121                    $scope.old_interface.ipv4.values[i].PrefixLength ||
122                $scope.interface.ipv4.values[i].Gateway !=
123                    $scope.old_interface.ipv4.values[i].Gateway) {
124              promises.push(setIPV4(i));
125            }
126          }
127        }
128
129        if (promises.length) {
130          $q.all(promises).finally(function() {
131            $scope.loading = false;
132            if (!$scope.set_network_error) {
133              $scope.set_network_success = true;
134              // Since an IPV4 interface (e.g. IP address, gateway, or netmask)
135              // edit is a delete then an add and the GUI can't calculate the
136              // interface id (e.g. 5c083707) beforehand and it is not returned
137              // by the REST call, openbmc#3227, reload the page after an edit,
138              // which makes a 2nd REST call.
139              // Do this for all network changes due to the possibility of a set
140              // network failing even though it returned success, openbmc#1641,
141              // and to update dataService and old_interface to know which
142              // data has changed if the user continues to edit network
143              // settings.
144              // TODO: The reload is not ideal. Revisit this.
145              $timeout(function() {
146                loadNetworkInfo();
147              }, 4000);
148            }
149          });
150        } else {
151          $scope.loading = false;
152        }
153
154      };
155
156      function setMACAddress() {
157        return APIUtils
158            .setMACAddress(
159                $scope.selectedInterface, $scope.interface.MACAddress)
160            .then(
161                function(data) {},
162                function(error) {
163                  console.log(JSON.stringify(error));
164                  $scope.set_network_error = 'MAC Address';
165                });
166      }
167
168      function setDefaultGateway() {
169        return APIUtils.setDefaultGateway($scope.defaultgateway)
170            .then(
171                function(data) {},
172                function(error) {
173                  console.log(JSON.stringify(error));
174                  $scope.set_network_error = 'Default Gateway';
175                });
176      }
177
178      function setHostname() {
179        return APIUtils.setHostname($scope.hostname)
180            .then(
181                function(data) {},
182                function(error) {
183                  console.log(JSON.stringify(error));
184                  $scope.set_network_error = 'Hostname';
185                });
186      }
187
188      function setDHCPEnabled() {
189        return APIUtils
190            .setDHCPEnabled(
191                $scope.selectedInterface, $scope.interface.DHCPEnabled)
192            .then(
193                function(data) {},
194                function(error) {
195                  console.log(JSON.stringify(error));
196                  $scope.set_network_error = 'DHCP';
197                });
198      }
199
200      function setNameservers() {
201        // Nameservers does not allow an empty array, since we remove all empty
202        // strings above, could have an empty array. TODO: openbmc/openbmc#3240
203        if ($scope.interface.Nameservers.length == 0) {
204          $scope.interface.Nameservers.push('');
205        }
206        return APIUtils
207            .setNameservers(
208                $scope.selectedInterface, $scope.interface.Nameservers)
209            .then(
210                function(data) {},
211                function(error) {
212                  console.log(JSON.stringify(error));
213                  $scope.set_network_error = 'DNS Servers';
214                });
215      }
216
217      function setIPV4(index) {
218        // The correct way to edit an IPV4 interface is to remove it and then
219        // add a new one
220        return APIUtils
221            .deleteIPV4(
222                $scope.selectedInterface, $scope.interface.ipv4.ids[index])
223            .then(
224                function(data) {
225                  return APIUtils
226                      .addIPV4(
227                          $scope.selectedInterface,
228                          $scope.interface.ipv4.values[index].Address,
229                          $scope.interface.ipv4.values[index].PrefixLength,
230                          $scope.interface.ipv4.values[index].Gateway)
231                      .then(
232                          function(data) {},
233                          function(error) {
234                            console.log(JSON.stringify(error));
235                            $scope.set_network_error =
236                                $scope.interface.ipv4.values[index].Address;
237                          });
238                },
239                function(error) {
240                  console.log(JSON.stringify(error));
241                  $scope.set_network_error =
242                      $scope.interface.ipv4.values[index].Address;
243                });
244      }
245
246      $scope.refresh = function() {
247        loadNetworkInfo();
248      };
249
250      function loadNetworkInfo() {
251        APIUtils.getNetworkInfo().then(function(data) {
252          dataService.setNetworkInfo(data);
253          $scope.network = data.formatted_data;
254          $scope.hostname = data.hostname;
255          $scope.defaultgateway = data.defaultgateway;
256          if ($scope.network.interface_ids.length) {
257            // Use the first network interface if the user hasn't chosen one
258            if (!$scope.selectedInterface ||
259                !$scope.network.interfaces[$scope.selectedInterface]) {
260              $scope.selectedInterface = $scope.network.interface_ids[0];
261            }
262            $scope.interface =
263                $scope.network.interfaces[$scope.selectedInterface];
264            // Copy the interface so we know later if changes were made to the
265            // page
266            $scope.old_interface = JSON.parse(JSON.stringify($scope.interface));
267          }
268        });
269      }
270    }
271  ]);
272
273})(angular);
274