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