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 $scope.loadFirmwares(); 156 }, function(error){ 157 $scope.uploading = false; 158 $scope.displayError({ 159 modal_title: 'Error during image upload', 160 title: 'Error during image upload', 161 desc: 'Error uploading image', 162 type: 'Error uploading image, please check the image' 163 }); 164 }); 165 } 166 } 167 168 $scope.download = function(){ 169 $scope.download_error_msg = ""; 170 if(!$scope.download_host || !$scope.download_filename){ 171 $scope.download_error_msg = "Field is required!"; 172 return false; 173 } 174 $scope.downloading = true; 175 APIUtils.downloadImage($scope.download_host, $scope.download_filename).then(function(response){ 176 $scope.downloading = false; 177 // TODO: refresh firmware page to display new image 178 }, function(error){ 179 $scope.downloading = false; 180 $scope.displayError({ 181 modal_title: 'Error during downloading Image', 182 title: 'Error during downloading Image', 183 desc: JSON.stringify(error), 184 type: 'Error' 185 }); 186 }); 187 } 188 189 $scope.changePriority = function(imageId, imageVersion, from, to){ 190 $scope.priority_image_id = imageId; 191 $scope.priority_image_version = imageVersion; 192 $scope.priority_from = from; 193 $scope.priority_to = to; 194 $scope.confirm_priority = true; 195 } 196 197 $scope.confirmChangePriority = function(){ 198 $scope.loading = true; 199 APIUtils.changePriority($scope.priority_image_id, $scope.priority_to).then(function(response){ 200 $scope.loading = false; 201 if(response.status == 'error'){ 202 $scope.displayError({ 203 modal_title: response.data.description, 204 title: response.data.description, 205 desc: response.data.exception, 206 type: 'Error' 207 }); 208 }else{ 209 $scope.loadFirmwares(); 210 } 211 }); 212 $scope.confirm_priority = false; 213 } 214 $scope.deleteImage = function(imageId, imageVersion){ 215 $scope.delete_image_id = imageId; 216 $scope.delete_image_version = imageVersion; 217 $scope.confirm_delete = true; 218 } 219 $scope.confirmDeleteImage = function(){ 220 $scope.loading = true; 221 APIUtils.deleteImage($scope.delete_image_id).then(function(response){ 222 $scope.loading = false; 223 if(response.status == 'error'){ 224 $scope.displayError({ 225 modal_title: response.data.description, 226 title: response.data.description, 227 desc: response.data.exception, 228 type: 'Error' 229 }); 230 }else{ 231 $scope.loadFirmwares(); 232 } 233 }); 234 $scope.confirm_delete = false; 235 } 236 $scope.fileNameChanged = function(){ 237 $scope.file_empty = false; 238 } 239 240 $scope.filters = { 241 bmc: { 242 imageType: 'BMC' 243 }, 244 host: { 245 imageType: 'Host' 246 } 247 }; 248 249 $scope.loadFirmwares = function(){ 250 APIUtils.getFirmwares().then(function(result){ 251 $scope.firmwares = result.data; 252 $scope.bmcActiveVersion = result.bmcActiveVersion; 253 $scope.hostActiveVersion = result.hostActiveVersion; 254 }); 255 } 256 257 $scope.loadFirmwares(); 258 } 259 ] 260 ); 261 262})(angular); 263