1/** 2 * Controller for firmware 3 * 4 * @module app/configuration 5 * @exports firmwareController 6 * @name firmwareController 7 */ 8 9window.angular && (function (angular) { 10 'use strict'; 11 12 angular 13 .module('app.configuration') 14 .controller('firmwareController', [ 15 '$scope', 16 '$window', 17 'APIUtils', 18 'dataService', 19 '$location', 20 '$anchorScroll', 21 'Constants', 22 '$interval', 23 '$q', 24 '$timeout', 25 function ($scope, $window, APIUtils, dataService, $location, $anchorScroll, Constants, $interval, $q, $timeout) { 26 $scope.dataService = dataService; 27 28 //Scroll to target anchor 29 $scope.gotoAnchor = function () { 30 $location.hash('upload'); 31 $anchorScroll(); 32 }; 33 34 $scope.firmwares = []; 35 $scope.bmcActiveVersion = ""; 36 $scope.hostActiveVersion = ""; 37 $scope.display_error = false; 38 $scope.activate_confirm = false; 39 $scope.delete_image_id = ""; 40 $scope.delete_image_version = ""; 41 $scope.activate_image_id = ""; 42 $scope.activate_image_version = ""; 43 $scope.activate_image_type = ""; 44 $scope.priority_image_id = ""; 45 $scope.priority_image_version = ""; 46 $scope.priority_from = -1; 47 $scope.priority_to = -1; 48 $scope.confirm_priority = false; 49 $scope.file_empty = true; 50 $scope.uploading = false; 51 $scope.activate = { reboot: true }; 52 $scope.download_error_msg = ""; 53 54 var pollActivationTimer = undefined; 55 56 $scope.error = { 57 modal_title: "", 58 title: "", 59 desc: "", 60 type: "warning" 61 }; 62 63 $scope.activateImage = function(imageId, imageVersion, imageType){ 64 $scope.activate_image_id = imageId; 65 $scope.activate_image_version = imageVersion; 66 $scope.activate_image_type = imageType; 67 $scope.activate_confirm = true; 68 } 69 70 $scope.displayError = function(data){ 71 $scope.error = data; 72 $scope.display_error = true; 73 } 74 75 function waitForActive(imageId){ 76 var deferred = $q.defer(); 77 var startTime = new Date(); 78 pollActivationTimer = $interval(function(){ 79 APIUtils.getActivation(imageId).then(function(state){ 80 //@TODO: display an error message if image "Failed" 81 if(((/\.Active$/).test(state.data)) || ((/\.Failed$/).test(state.data))){ 82 $interval.cancel(pollActivationTimer); 83 pollActivationTimer = undefined; 84 deferred.resolve(state); 85 } 86 }, function(error){ 87 $interval.cancel(pollActivationTimer); 88 pollActivationTimer = undefined; 89 console.log(error); 90 deferred.reject(error); 91 }); 92 var now = new Date(); 93 if((now.getTime() - startTime.getTime()) >= Constants.TIMEOUT.ACTIVATION){ 94 $interval.cancel(pollActivationTimer); 95 pollActivationTimer = undefined; 96 console.log("Time out activating image, " + imageId); 97 deferred.reject("Time out. Image did not activate in allotted time."); 98 } 99 }, Constants.POLL_INTERVALS.ACTIVATION); 100 return deferred.promise; 101 } 102 103 $scope.activateConfirmed = function(){ 104 APIUtils.activateImage($scope.activate_image_id).then(function(state){ 105 $scope.loadFirmwares(); 106 return state; 107 }, function(error){ 108 $scope.displayError({ 109 modal_title: 'Error during activation call', 110 title: 'Error during activation call', 111 desc: JSON.stringify(error.data), 112 type: 'Error' 113 }); 114 }).then(function(activationState){ 115 waitForActive($scope.activate_image_id).then(function(state){ 116 $scope.loadFirmwares(); 117 }, function(error){ 118 $scope.displayError({ 119 modal_title: 'Error during image activation', 120 title: 'Error during image activation', 121 desc: JSON.stringify(error.data), 122 type: 'Error' 123 }); 124 }).then(function(state){ 125 if($scope.activate.reboot){ 126 // Despite the new image being active, issue, 127 // https://github.com/openbmc/openbmc/issues/2764, can cause a 128 // system to brick, if the system reboots before the service to set 129 // the U-Boot variables is complete. Wait 10 seconds before rebooting 130 // to ensure this service is complete. This issue is fixed in newer images, but 131 // the user may be updating from an older image that does not that have this fix. 132 // TODO: remove this timeout after sufficient time has passed. 133 $timeout(function() { 134 APIUtils.bmcReboot(function(response){}, function(error){ 135 $scope.displayError({ 136 modal_title: 'Error during BMC reboot', 137 title: 'Error during BMC reboot', 138 desc: JSON.stringify(error.data), 139 type: 'Error' 140 }); 141 }); 142 }, 10000); 143 } 144 }); 145 }); 146 $scope.activate_confirm = false; 147 } 148 149 $scope.upload = function(){ 150 if($scope.file) { 151 $scope.uploading = true; 152 APIUtils.uploadImage($scope.file).then(function(response){ 153 $scope.uploading = false; 154 $scope.loadFirmwares(); 155 }, function(error){ 156 $scope.uploading = false; 157 $scope.displayError({ 158 modal_title: 'Error during image upload', 159 title: 'Error during image upload', 160 desc: 'Error uploading image', 161 type: 'Error uploading image, please check the image' 162 }); 163 }); 164 } 165 } 166 167 $scope.download = function(){ 168 $scope.download_error_msg = ""; 169 if(!$scope.download_host || !$scope.download_filename){ 170 $scope.download_error_msg = "Field is required!"; 171 return false; 172 } 173 $scope.downloading = true; 174 APIUtils.downloadImage($scope.download_host, $scope.download_filename).then(function(response){ 175 $scope.downloading = false; 176 // TODO: refresh firmware page to display new image 177 }, function(error){ 178 $scope.downloading = false; 179 $scope.displayError({ 180 modal_title: 'Error during downloading Image', 181 title: 'Error during downloading Image', 182 desc: JSON.stringify(error), 183 type: 'Error' 184 }); 185 }); 186 } 187 188 $scope.changePriority = function(imageId, imageVersion, from, to){ 189 $scope.priority_image_id = imageId; 190 $scope.priority_image_version = imageVersion; 191 $scope.priority_from = from; 192 $scope.priority_to = to; 193 $scope.confirm_priority = true; 194 } 195 196 $scope.confirmChangePriority = function(){ 197 $scope.loading = true; 198 APIUtils.changePriority($scope.priority_image_id, $scope.priority_to).then(function(response){ 199 $scope.loading = false; 200 if(response.status == 'error'){ 201 $scope.displayError({ 202 modal_title: response.data.description, 203 title: response.data.description, 204 desc: response.data.exception, 205 type: 'Error' 206 }); 207 }else{ 208 $scope.loadFirmwares(); 209 } 210 }); 211 $scope.confirm_priority = false; 212 } 213 $scope.deleteImage = function(imageId, imageVersion){ 214 $scope.delete_image_id = imageId; 215 $scope.delete_image_version = imageVersion; 216 $scope.confirm_delete = true; 217 } 218 $scope.confirmDeleteImage = function(){ 219 $scope.loading = true; 220 APIUtils.deleteImage($scope.delete_image_id).then(function(response){ 221 $scope.loading = false; 222 if(response.status == 'error'){ 223 $scope.displayError({ 224 modal_title: response.data.description, 225 title: response.data.description, 226 desc: response.data.exception, 227 type: 'Error' 228 }); 229 }else{ 230 $scope.loadFirmwares(); 231 } 232 }); 233 $scope.confirm_delete = false; 234 } 235 $scope.fileNameChanged = function(){ 236 $scope.file_empty = false; 237 } 238 239 $scope.filters = { 240 bmc: { 241 imageType: 'BMC' 242 }, 243 host: { 244 imageType: 'Host' 245 } 246 }; 247 248 $scope.loadFirmwares = function(){ 249 APIUtils.getFirmwares().then(function(result){ 250 $scope.firmwares = result.data; 251 $scope.bmcActiveVersion = result.bmcActiveVersion; 252 $scope.hostActiveVersion = result.hostActiveVersion; 253 }); 254 } 255 256 $scope.loadFirmwares(); 257 } 258 ] 259 ); 260 261})(angular); 262