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