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