blob: 451c16ce98ebd7d2d3393d7d71c68841107d54a7 [file] [log] [blame]
Michael Davis43366db2017-05-15 18:12:35 -05001/**
2 * Controller for firmware
3 *
4 * @module app/configuration
5 * @exports firmwareController
6 * @name firmwareController
Michael Davis43366db2017-05-15 18:12:35 -05007 */
8
Andrew Geisslerba5e3f32018-05-24 10:58:00 -07009window.angular && (function(angular) {
10 'use strict';
Michael Davis43366db2017-05-15 18:12:35 -050011
Andrew Geisslerd27bb132018-05-24 11:07:27 -070012 angular.module('app.configuration').controller('firmwareController', [
Gunnar Mills806d39b2018-09-26 11:47:25 -050013 '$scope', '$window', 'APIUtils', 'dataService', '$location',
Gunnar Mills6f4e12e2019-05-23 11:11:42 -050014 '$anchorScroll', 'Constants', '$interval', '$q', '$timeout', 'toastService',
Andrew Geisslerd27bb132018-05-24 11:07:27 -070015 function(
Gunnar Mills806d39b2018-09-26 11:47:25 -050016 $scope, $window, APIUtils, dataService, $location, $anchorScroll,
Gunnar Mills6f4e12e2019-05-23 11:11:42 -050017 Constants, $interval, $q, $timeout, toastService) {
Gunnar Mills806d39b2018-09-26 11:47:25 -050018 $scope.dataService = dataService;
19
Andrew Geisslerd27bb132018-05-24 11:07:27 -070020 // Scroll to target anchor
21 $scope.gotoAnchor = function() {
22 $location.hash('upload');
23 $anchorScroll();
24 };
Iftekharul Islamc0161392017-06-14 15:46:15 -050025
Andrew Geisslerd27bb132018-05-24 11:07:27 -070026 $scope.firmwares = [];
27 $scope.bmcActiveVersion = '';
28 $scope.hostActiveVersion = '';
Andrew Geisslerd27bb132018-05-24 11:07:27 -070029 $scope.activate_confirm = false;
30 $scope.delete_image_id = '';
31 $scope.delete_image_version = '';
32 $scope.activate_image_id = '';
33 $scope.activate_image_version = '';
34 $scope.activate_image_type = '';
35 $scope.priority_image_id = '';
36 $scope.priority_image_version = '';
37 $scope.priority_from = -1;
38 $scope.priority_to = -1;
39 $scope.confirm_priority = false;
40 $scope.file_empty = true;
41 $scope.uploading = false;
Andrew Geisslerd27bb132018-05-24 11:07:27 -070042 $scope.activate = {reboot: true};
Iftekharul Islamc0161392017-06-14 15:46:15 -050043
Andrew Geisslerd27bb132018-05-24 11:07:27 -070044 var pollActivationTimer = undefined;
45 var pollDownloadTimer = undefined;
Gunnar Mills033025f2018-03-06 14:49:40 -060046
Andrew Geisslerd27bb132018-05-24 11:07:27 -070047 $scope.error = {modal_title: '', title: '', desc: '', type: 'warning'};
Iftekharul Islamc0161392017-06-14 15:46:15 -050048
Andrew Geisslerd27bb132018-05-24 11:07:27 -070049 $scope.activateImage = function(imageId, imageVersion, imageType) {
50 $scope.activate_image_id = imageId;
51 $scope.activate_image_version = imageVersion;
52 $scope.activate_image_type = imageType;
53 $scope.activate_confirm = true;
54 };
Iftekharul Islamc0161392017-06-14 15:46:15 -050055
Andrew Geisslerd27bb132018-05-24 11:07:27 -070056 function waitForActive(imageId) {
57 var deferred = $q.defer();
58 var startTime = new Date();
59 pollActivationTimer = $interval(function() {
60 APIUtils.getActivation(imageId).then(
61 function(state) {
Dixsie Wolmersff7f1062019-10-04 12:49:32 -050062 let imageStateActive = (/\.Active$/).test(state.data);
63 let imageStateFailed = (/\.Failed$/).test(state.data);
64 if (imageStateActive || imageStateFailed) {
Andrew Geisslerd27bb132018-05-24 11:07:27 -070065 $interval.cancel(pollActivationTimer);
66 pollActivationTimer = undefined;
Dixsie Wolmersff7f1062019-10-04 12:49:32 -050067 }
68 if (imageStateActive) {
Andrew Geisslerd27bb132018-05-24 11:07:27 -070069 deferred.resolve(state);
Dixsie Wolmersff7f1062019-10-04 12:49:32 -050070 } else if (imageStateFailed) {
71 console.log('Image failed to activate: ', imageStateFailed);
72 toastService.error('Image failed to activate.');
73 deferred.reject(error);
Andrew Geisslerd27bb132018-05-24 11:07:27 -070074 }
75 },
76 function(error) {
Andrew Geisslerba5e3f32018-05-24 10:58:00 -070077 $interval.cancel(pollActivationTimer);
78 pollActivationTimer = undefined;
Andrew Geisslerd27bb132018-05-24 11:07:27 -070079 console.log(error);
80 deferred.reject(error);
Andrew Geisslerba5e3f32018-05-24 10:58:00 -070081 });
Andrew Geisslerd27bb132018-05-24 11:07:27 -070082 var now = new Date();
83 if ((now.getTime() - startTime.getTime()) >=
84 Constants.TIMEOUT.ACTIVATION) {
85 $interval.cancel(pollActivationTimer);
86 pollActivationTimer = undefined;
87 console.log('Time out activating image, ' + imageId);
88 deferred.reject(
89 'Time out. Image did not activate in allotted time.');
90 }
91 }, Constants.POLL_INTERVALS.ACTIVATION);
92 return deferred.promise;
93 }
94
95 $scope.activateConfirmed = function() {
96 APIUtils.activateImage($scope.activate_image_id)
97 .then(
98 function(state) {
99 $scope.loadFirmwares();
100 return state;
101 },
102 function(error) {
beccabroek90ae95e2019-01-15 16:55:57 -0600103 console.log(JSON.stringify(error));
beccabroek27ce84d2019-02-05 15:43:17 -0600104 toastService.error('Unable to activate image');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700105 })
106 .then(function(activationState) {
107 waitForActive($scope.activate_image_id)
108 .then(
109 function(state) {
110 $scope.loadFirmwares();
111 },
112 function(error) {
beccabroek90ae95e2019-01-15 16:55:57 -0600113 console.log(JSON.stringify(error));
beccabroek27ce84d2019-02-05 15:43:17 -0600114 toastService.error('Unable to activate image');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700115 })
116 .then(function(state) {
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700117 if ($scope.activate.reboot &&
118 ($scope.activate_image_type == 'BMC')) {
Yoshie Muranakac10fce52019-11-11 07:44:33 -0800119 APIUtils.bmcReboot().then(
120 function(response) {
121 toastService.success('BMC is rebooting.')
122 },
123 function(error) {
124 console.log(JSON.stringify(error));
125 toastService.error('Unable to reboot BMC.');
126 });
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700127 }
beccabroekc3abaa92018-08-14 13:47:18 -0500128 if ($scope.activate.reboot &&
129 ($scope.activate_image_type == 'Host')) {
130 // If image type being activated is a host image, the
131 // current power status of the server determines if the
132 // server should power on or reboot.
133 if ($scope.isServerOff()) {
134 powerOn();
135 } else {
136 warmReboot();
137 }
138 }
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700139 });
140 });
141 $scope.activate_confirm = false;
142 };
beccabroekc3abaa92018-08-14 13:47:18 -0500143 function powerOn() {
144 dataService.setUnreachableState();
145 APIUtils.hostPowerOn()
146 .then(function(response) {
147 return response;
148 })
149 .then(function(lastStatus) {
150 return APIUtils.pollHostStatusTillOn();
151 })
152 .catch(function(error) {
beccabroek90ae95e2019-01-15 16:55:57 -0600153 console.log(JSON.stringify(error));
beccabroek27ce84d2019-02-05 15:43:17 -0600154 toastService.error(Constants.MESSAGES.POWER_OP.POWER_ON_FAILED);
beccabroekc3abaa92018-08-14 13:47:18 -0500155 });
156 };
157 function warmReboot() {
158 $scope.uploading = true;
159 dataService.setUnreachableState();
160 APIUtils.hostReboot()
161 .then(function(response) {
162 return response;
163 })
164 .then(function(lastStatus) {
165 return APIUtils.pollHostStatusTilReboot();
166 })
167 .catch(function(error) {
beccabroek90ae95e2019-01-15 16:55:57 -0600168 console.log(JSON.stringify(error));
beccabroek27ce84d2019-02-05 15:43:17 -0600169 toastService.error(
170 Constants.MESSAGES.POWER_OP.WARM_REBOOT_FAILED);
beccabroekc3abaa92018-08-14 13:47:18 -0500171 });
172 };
173 $scope.isServerOff = function() {
174 return dataService.server_state === Constants.HOST_STATE_TEXT.off;
175 };
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700176
177 $scope.upload = function() {
178 if ($scope.file) {
179 $scope.uploading = true;
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700180 APIUtils.uploadImage($scope.file)
181 .then(
182 function(response) {
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700183 $scope.uploading = false;
beccabroek27ce84d2019-02-05 15:43:17 -0600184 toastService.success(
beccabroek90ae95e2019-01-15 16:55:57 -0600185 'Image file "' + $scope.file.name +
186 '" has been uploaded');
187 $scope.file = '';
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700188 $scope.loadFirmwares();
189 },
190 function(error) {
191 $scope.uploading = false;
192 console.log(error);
beccabroek27ce84d2019-02-05 15:43:17 -0600193 toastService.error('Unable to upload image file');
Andrew Geisslerba5e3f32018-05-24 10:58:00 -0700194 });
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700195 }
196 };
Iftekharul Islamc0161392017-06-14 15:46:15 -0500197
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700198 // TODO: openbmc/openbmc#1691 Add support to return
199 // the id of the newly created image, downloaded via
200 // tftp. Polling the number of software objects is a
201 // near term solution.
202 function waitForDownload() {
203 var deferred = $q.defer();
204 var startTime = new Date();
205 pollDownloadTimer = $interval(function() {
206 var now = new Date();
207 if ((now.getTime() - startTime.getTime()) >=
208 Constants.TIMEOUT.DOWNLOAD_IMAGE) {
209 $interval.cancel(pollDownloadTimer);
210 pollDownloadTimer = undefined;
211 deferred.reject(
212 new Error(Constants.MESSAGES.POLL.DOWNLOAD_IMAGE_TIMEOUT));
Andrew Geisslerba5e3f32018-05-24 10:58:00 -0700213 }
Iftekharul Islamc0161392017-06-14 15:46:15 -0500214
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700215 APIUtils.getFirmwares().then(
216 function(response) {
217 if (response.data.length === $scope.firmwares.length + 1) {
218 $interval.cancel(pollDownloadTimer);
219 pollDownloadTimer = undefined;
220 deferred.resolve(response.data);
221 }
222 },
223 function(error) {
Andrew Geisslerba5e3f32018-05-24 10:58:00 -0700224 $interval.cancel(pollDownloadTimer);
225 pollDownloadTimer = undefined;
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700226 deferred.reject(error);
227 });
228 }, Constants.POLL_INTERVALS.DOWNLOAD_IMAGE);
CamVan Nguyen58301ec2018-04-20 21:33:01 -0500229
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700230 return deferred.promise;
231 }
232
233 $scope.download = function() {
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700234 if (!$scope.download_host || !$scope.download_filename) {
beccabroek27ce84d2019-02-05 15:43:17 -0600235 toastService.error(
236 'TFTP server IP address and file name are required!');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700237 return false;
Andrew Geisslerba5e3f32018-05-24 10:58:00 -0700238 }
CamVan Nguyen58301ec2018-04-20 21:33:01 -0500239
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700240 $scope.downloading = true;
241 APIUtils.getFirmwares()
242 .then(function(response) {
243 $scope.firmwares = response.data;
244 })
245 .then(function() {
246 return APIUtils
247 .downloadImage($scope.download_host, $scope.download_filename)
248 .then(function(downloadStatus) {
249 return downloadStatus;
250 });
251 })
252 .then(function(downloadStatus) {
253 return waitForDownload();
254 })
255 .then(
256 function(newFirmwareList) {
257 $scope.download_host = '';
258 $scope.download_filename = '';
259 $scope.downloading = false;
beccabroek27ce84d2019-02-05 15:43:17 -0600260 toastService.success('Download complete');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700261 $scope.loadFirmwares();
262 },
263 function(error) {
264 console.log(error);
beccabroek27ce84d2019-02-05 15:43:17 -0600265 toastService.error(
beccabroek90ae95e2019-01-15 16:55:57 -0600266 'Image file from TFTP server "' + $scope.download_host +
267 '" could not be downloaded');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700268 $scope.downloading = false;
269 });
270 };
CamVan Nguyen58301ec2018-04-20 21:33:01 -0500271
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700272 $scope.changePriority = function(imageId, imageVersion, from, to) {
273 $scope.priority_image_id = imageId;
274 $scope.priority_image_version = imageVersion;
275 $scope.priority_from = from;
276 $scope.priority_to = to;
277 $scope.confirm_priority = true;
278 };
279
280 $scope.confirmChangePriority = function() {
281 $scope.loading = true;
282 APIUtils.changePriority($scope.priority_image_id, $scope.priority_to)
283 .then(function(response) {
284 $scope.loading = false;
285 if (response.status == 'error') {
beccabroek27ce84d2019-02-05 15:43:17 -0600286 toastService.error('Unable to update boot priority');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700287 } else {
288 $scope.loadFirmwares();
289 }
Andrew Geisslerba5e3f32018-05-24 10:58:00 -0700290 });
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700291 $scope.confirm_priority = false;
292 };
293 $scope.deleteImage = function(imageId, imageVersion) {
294 $scope.delete_image_id = imageId;
295 $scope.delete_image_version = imageVersion;
296 $scope.confirm_delete = true;
297 };
298 $scope.confirmDeleteImage = function() {
299 $scope.loading = true;
300 APIUtils.deleteImage($scope.delete_image_id).then(function(response) {
301 $scope.loading = false;
302 if (response.status == 'error') {
beccabroek27ce84d2019-02-05 15:43:17 -0600303 toastService.error('Unable to delete image');
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700304 } else {
305 $scope.loadFirmwares();
Andrew Geisslerba5e3f32018-05-24 10:58:00 -0700306 }
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700307 });
308 $scope.confirm_delete = false;
309 };
Iftekharul Islamc0161392017-06-14 15:46:15 -0500310
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700311 $scope.filters = {bmc: {imageType: 'BMC'}, host: {imageType: 'Host'}};
Iftekharul Islamc0161392017-06-14 15:46:15 -0500312
Andrew Geisslerd27bb132018-05-24 11:07:27 -0700313 $scope.loadFirmwares = function() {
314 APIUtils.getFirmwares().then(function(result) {
315 $scope.firmwares = result.data;
316 $scope.bmcActiveVersion = result.bmcActiveVersion;
317 $scope.hostActiveVersion = result.hostActiveVersion;
318 });
319 };
320
321 $scope.loadFirmwares();
322 }
323 ]);
Michael Davis43366db2017-05-15 18:12:35 -0500324})(angular);