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 'toastService', 15 function( 16 $scope, $window, APIUtils, dataService, $timeout, $route, $q, 17 toastService) { 18 $scope.dataService = dataService; 19 $scope.network = {}; 20 $scope.oldInterface = {}; 21 $scope.interface = {}; 22 $scope.networkDevice = false; 23 $scope.hostname = ''; 24 $scope.defaultGateway = ''; 25 $scope.selectedInterface = ''; 26 $scope.confirmSettings = false; 27 $scope.loading = false; 28 $scope.ipv4sToDelete = []; 29 30 loadNetworkInfo(); 31 32 $scope.selectInterface = function(interfaceId) { 33 $scope.interface = $scope.network.interfaces[interfaceId]; 34 // Copy the interface so we know later if changes were made to the page 35 $scope.oldInterface = JSON.parse(JSON.stringify($scope.interface)); 36 $scope.selectedInterface = interfaceId; 37 $scope.networkDevice = false; 38 }; 39 40 $scope.addDNSField = function() { 41 $scope.interface.Nameservers.push(''); 42 }; 43 44 $scope.removeDNSField = function(index) { 45 $scope.interface.Nameservers.splice(index, 1); 46 }; 47 48 $scope.addIpv4Field = function() { 49 $scope.interface.ipv4.values.push( 50 {Address: '', PrefixLength: '', Gateway: ''}); 51 }; 52 53 $scope.removeIpv4Address = function(index) { 54 // Check if the IPV4 being removed has an id. This indicates that it is 55 // an existing address and needs to be removed in the back end. 56 if ($scope.interface.ipv4.values[index].id) { 57 $scope.ipv4sToDelete.push($scope.interface.ipv4.values[index]); 58 } 59 $scope.interface.ipv4.values.splice(index, 1); 60 }; 61 62 $scope.setNetworkSettings = function() { 63 // Hides the confirm network settings modal 64 $scope.confirmSettings = false; 65 $scope.loading = true; 66 var promises = []; 67 68 // MAC Address are case-insensitive 69 if ($scope.interface.MACAddress.toLowerCase() != 70 dataService.mac_address.toLowerCase()) { 71 promises.push(setMACAddress()); 72 } 73 if ($scope.defaultGateway != dataService.defaultgateway) { 74 promises.push(setDefaultGateway()); 75 } 76 if ($scope.hostname != dataService.hostname) { 77 promises.push(setHostname()); 78 } 79 if ($scope.interface.DHCPEnabled != $scope.oldInterface.DHCPEnabled) { 80 promises.push(setDHCPEnabled()); 81 } 82 83 // Remove any empty strings from the array. Important because we add an 84 // empty string to the end so the user can add a new DNS server, if the 85 // user doesn't fill out the field, we don't want to add. 86 $scope.interface.Nameservers = 87 $scope.interface.Nameservers.filter(Boolean); 88 // toString() is a cheap way to compare 2 string arrays 89 if ($scope.interface.Nameservers.toString() != 90 $scope.oldInterface.Nameservers.toString()) { 91 promises.push(setNameservers()); 92 } 93 94 // Set IPV4 IP Addresses, Netmask Prefix Lengths, and Gateways 95 if (!$scope.interface.DHCPEnabled) { 96 // Delete existing IPV4 addresses that were removed 97 promises.push(removeIPV4s()); 98 // Update any changed IPV4 addresses and add new 99 for (var i in $scope.interface.ipv4.values) { 100 if (!APIUtils.validIPV4IP( 101 $scope.interface.ipv4.values[i].Address)) { 102 toastService.error( 103 $scope.interface.ipv4.values[i].Address + 104 ' invalid IP parameter'); 105 $scope.loading = false; 106 return; 107 } 108 if (!APIUtils.validIPV4IP( 109 $scope.interface.ipv4.values[i].Gateway)) { 110 toastService.error( 111 $scope.interface.ipv4.values[i].Address + 112 ' invalid gateway parameter'); 113 $scope.loading = false; 114 return; 115 } 116 // The netmask prefix length will be undefined if outside range 117 if (!$scope.interface.ipv4.values[i].PrefixLength) { 118 toastService.error( 119 $scope.interface.ipv4.values[i].Address + 120 ' invalid Prefix Length parameter'); 121 $scope.loading = false; 122 return; 123 } 124 if ($scope.interface.ipv4.values[i].updateAddress || 125 $scope.interface.ipv4.values[i].updateGateway || 126 $scope.interface.ipv4.values[i].updatePrefix) { 127 // If IPV4 has an id it means it already exists in the back end, 128 // and in order to update it is required to remove previous IPV4 129 // address and add new one. See openbmc/openbmc/issues/2163. 130 // TODO: update to use PUT once issue 2163 is resolved. 131 if ($scope.interface.ipv4.values[i].id) { 132 promises.push(updateIPV4(i)); 133 } else { 134 promises.push(addIPV4(i)); 135 } 136 } 137 } 138 } 139 140 if (promises.length) { 141 $q.all(promises).then( 142 function(response) { 143 // Since an IPV4 interface (e.g. IP address, gateway, or 144 // netmask) edit is a delete then an add and the GUI can't 145 // calculate the interface id (e.g. 5c083707) beforehand and it 146 // is not returned by the REST call, openbmc#3227, reload the 147 // page after an edit, which makes a 2nd REST call. Do this for 148 // all network changes due to the possibility of a set network 149 // failing even though it returned success, openbmc#1641, and to 150 // update dataService and oldInterface to know which data has 151 // changed if the user continues to edit network settings. 152 // TODO: The reload is not ideal. Revisit this. 153 $timeout(function() { 154 loadNetworkInfo(); 155 $scope.loading = false; 156 toastService.success('Network settings saved'); 157 }, 4000); 158 }, 159 function(error) { 160 $scope.loading = false; 161 toastService.error('Network settings could not be saved'); 162 }) 163 } else { 164 $scope.loading = false; 165 } 166 }; 167 168 function setMACAddress() { 169 return APIUtils 170 .setMACAddress( 171 $scope.selectedInterface, $scope.interface.MACAddress) 172 .then( 173 function(data) {}, 174 function(error) { 175 console.log(JSON.stringify(error)); 176 return $q.reject(); 177 }); 178 } 179 180 function setDefaultGateway() { 181 return APIUtils.setDefaultGateway($scope.defaultGateway) 182 .then( 183 function(data) {}, 184 function(error) { 185 console.log(JSON.stringify(error)); 186 return $q.reject(); 187 }); 188 } 189 190 function setHostname() { 191 return APIUtils.setHostname($scope.hostname) 192 .then( 193 function(data) {}, 194 function(error) { 195 console.log(JSON.stringify(error)); 196 return $q.reject(); 197 }); 198 } 199 200 function setDHCPEnabled() { 201 return APIUtils 202 .setDHCPEnabled( 203 $scope.selectedInterface, $scope.interface.DHCPEnabled) 204 .then( 205 function(data) {}, 206 function(error) { 207 console.log(JSON.stringify(error)); 208 return $q.reject(); 209 }); 210 } 211 212 function setNameservers() { 213 // Nameservers does not allow an empty array, since we remove all empty 214 // strings above, could have an empty array. TODO: openbmc/openbmc#3240 215 if ($scope.interface.Nameservers.length == 0) { 216 $scope.interface.Nameservers.push(''); 217 } 218 return APIUtils 219 .setNameservers( 220 $scope.selectedInterface, $scope.interface.Nameservers) 221 .then( 222 function(data) {}, 223 function(error) { 224 console.log(JSON.stringify(error)); 225 return $q.reject(); 226 }); 227 } 228 229 function removeIPV4s() { 230 return $scope.ipv4sToDelete.map(function(ipv4) { 231 return APIUtils.deleteIPV4($scope.selectedInterface, ipv4.id) 232 .then( 233 function(data) {}, 234 function(error) { 235 console.log(JSON.stringify(error)); 236 return $q.reject(); 237 }) 238 }); 239 } 240 241 function addIPV4(index) { 242 return APIUtils 243 .addIPV4( 244 $scope.selectedInterface, 245 $scope.interface.ipv4.values[index].Address, 246 $scope.interface.ipv4.values[index].PrefixLength, 247 $scope.interface.ipv4.values[index].Gateway) 248 .then( 249 function(data) {}, 250 function(error) { 251 console.log(JSON.stringify(error)); 252 return $q.reject(); 253 }) 254 } 255 256 function updateIPV4(index) { 257 // The correct way to edit an IPV4 interface is to remove it and then 258 // add a new one 259 return APIUtils 260 .deleteIPV4( 261 $scope.selectedInterface, 262 $scope.interface.ipv4.values[index].id) 263 .then( 264 function(data) { 265 return APIUtils 266 .addIPV4( 267 $scope.selectedInterface, 268 $scope.interface.ipv4.values[index].Address, 269 $scope.interface.ipv4.values[index].PrefixLength, 270 $scope.interface.ipv4.values[index].Gateway) 271 .then( 272 function(data) {}, 273 function(error) { 274 console.log(JSON.stringify(error)); 275 return $q.reject(); 276 }); 277 }, 278 function(error) { 279 console.log(JSON.stringify(error)); 280 return $q.reject(); 281 }); 282 } 283 284 $scope.refresh = function() { 285 loadNetworkInfo(); 286 }; 287 288 function loadNetworkInfo() { 289 APIUtils.getNetworkInfo().then(function(data) { 290 dataService.setNetworkInfo(data); 291 $scope.network = data.formatted_data; 292 $scope.hostname = data.hostname; 293 $scope.defaultGateway = data.defaultgateway; 294 if ($scope.network.interface_ids.length) { 295 // Use the first network interface if the user hasn't chosen one 296 if (!$scope.selectedInterface || 297 !$scope.network.interfaces[$scope.selectedInterface]) { 298 $scope.selectedInterface = $scope.network.interface_ids[0]; 299 } 300 $scope.interface = 301 $scope.network.interfaces[$scope.selectedInterface]; 302 // Copy the interface so we know later if changes were made to the 303 // page 304 $scope.oldInterface = JSON.parse(JSON.stringify($scope.interface)); 305 } 306 // Add id values and update flags to corresponding IPV4 objects 307 for (var i = 0; i < $scope.interface.ipv4.values.length; i++) { 308 $scope.interface.ipv4.values[i].id = $scope.interface.ipv4.ids[i]; 309 $scope.interface.ipv4.values[i].updateAddress = false; 310 $scope.interface.ipv4.values[i].updateGateway = false; 311 $scope.interface.ipv4.values[i].updatePrefix = false; 312 } 313 }); 314 } 315 } 316 ]); 317})(angular); 318