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