xref: /openbmc/phosphor-webui/app/configuration/controllers/firmware-controller.js (revision c10fce5b9497eea5ff36160adf0497c62b53a549)
143366db7SMichael Davis/**
243366db7SMichael Davis * Controller for firmware
343366db7SMichael Davis *
443366db7SMichael Davis * @module app/configuration
543366db7SMichael Davis * @exports firmwareController
643366db7SMichael Davis * @name firmwareController
743366db7SMichael Davis */
843366db7SMichael Davis
943366db7SMichael Daviswindow.angular && (function(angular) {
1043366db7SMichael Davis  'use strict';
1143366db7SMichael Davis
12d27bb135SAndrew Geissler  angular.module('app.configuration').controller('firmwareController', [
13806d39beSGunnar Mills    '$scope', '$window', 'APIUtils', 'dataService', '$location',
146f4e12e3SGunnar Mills    '$anchorScroll', 'Constants', '$interval', '$q', '$timeout', 'toastService',
15d27bb135SAndrew Geissler    function(
16806d39beSGunnar Mills        $scope, $window, APIUtils, dataService, $location, $anchorScroll,
176f4e12e3SGunnar Mills        Constants, $interval, $q, $timeout, toastService) {
18806d39beSGunnar Mills      $scope.dataService = dataService;
19806d39beSGunnar Mills
2043366db7SMichael Davis      // Scroll to target anchor
2143366db7SMichael Davis      $scope.gotoAnchor = function() {
2243366db7SMichael Davis        $location.hash('upload');
2343366db7SMichael Davis        $anchorScroll();
2443366db7SMichael Davis      };
25c016139fSIftekharul Islam
26c016139fSIftekharul Islam      $scope.firmwares = [];
27ba5e3f34SAndrew Geissler      $scope.bmcActiveVersion = '';
28ba5e3f34SAndrew Geissler      $scope.hostActiveVersion = '';
29e7f83970SGunnar Mills      $scope.activate_confirm = false;
30ba5e3f34SAndrew Geissler      $scope.delete_image_id = '';
31ba5e3f34SAndrew Geissler      $scope.delete_image_version = '';
32ba5e3f34SAndrew Geissler      $scope.activate_image_id = '';
33ba5e3f34SAndrew Geissler      $scope.activate_image_version = '';
34ba5e3f34SAndrew Geissler      $scope.activate_image_type = '';
35ba5e3f34SAndrew Geissler      $scope.priority_image_id = '';
36ba5e3f34SAndrew Geissler      $scope.priority_image_version = '';
371acb412dSIftekharul Islam      $scope.priority_from = -1;
381acb412dSIftekharul Islam      $scope.priority_to = -1;
391acb412dSIftekharul Islam      $scope.confirm_priority = false;
40c016139fSIftekharul Islam      $scope.file_empty = true;
41c016139fSIftekharul Islam      $scope.uploading = false;
42d27bb135SAndrew Geissler      $scope.activate = {reboot: true};
43c016139fSIftekharul Islam
44033025f3SGunnar Mills      var pollActivationTimer = undefined;
4558301ec8SCamVan Nguyen      var pollDownloadTimer = undefined;
46033025f3SGunnar Mills
47d27bb135SAndrew Geissler      $scope.error = {modal_title: '', title: '', desc: '', type: 'warning'};
48c016139fSIftekharul Islam
49ee6efd85SGunnar Mills      $scope.activateImage = function(imageId, imageVersion, imageType) {
50c016139fSIftekharul Islam        $scope.activate_image_id = imageId;
51e7f83970SGunnar Mills        $scope.activate_image_version = imageVersion;
52ee6efd85SGunnar Mills        $scope.activate_image_type = imageType;
53e7f83970SGunnar Mills        $scope.activate_confirm = true;
54ba5e3f34SAndrew Geissler      };
55c016139fSIftekharul Islam
56033025f3SGunnar Mills      function waitForActive(imageId) {
57033025f3SGunnar Mills        var deferred = $q.defer();
58033025f3SGunnar Mills        var startTime = new Date();
59033025f3SGunnar Mills        pollActivationTimer = $interval(function() {
60d27bb135SAndrew Geissler          APIUtils.getActivation(imageId).then(
61d27bb135SAndrew Geissler              function(state) {
62*ff7f1068SDixsie Wolmers                let imageStateActive = (/\.Active$/).test(state.data);
63*ff7f1068SDixsie Wolmers                let imageStateFailed = (/\.Failed$/).test(state.data);
64*ff7f1068SDixsie Wolmers                if (imageStateActive || imageStateFailed) {
65033025f3SGunnar Mills                  $interval.cancel(pollActivationTimer);
66033025f3SGunnar Mills                  pollActivationTimer = undefined;
67*ff7f1068SDixsie Wolmers                }
68*ff7f1068SDixsie Wolmers                if (imageStateActive) {
69033025f3SGunnar Mills                  deferred.resolve(state);
70*ff7f1068SDixsie Wolmers                } else if (imageStateFailed) {
71*ff7f1068SDixsie Wolmers                  console.log('Image failed to activate: ', imageStateFailed);
72*ff7f1068SDixsie Wolmers                  toastService.error('Image failed to activate.');
73*ff7f1068SDixsie Wolmers                  deferred.reject(error);
74033025f3SGunnar Mills                }
75d27bb135SAndrew Geissler              },
76d27bb135SAndrew Geissler              function(error) {
77033025f3SGunnar Mills                $interval.cancel(pollActivationTimer);
78033025f3SGunnar Mills                pollActivationTimer = undefined;
79033025f3SGunnar Mills                console.log(error);
80033025f3SGunnar Mills                deferred.reject(error);
81033025f3SGunnar Mills              });
82033025f3SGunnar Mills          var now = new Date();
83d27bb135SAndrew Geissler          if ((now.getTime() - startTime.getTime()) >=
84d27bb135SAndrew Geissler              Constants.TIMEOUT.ACTIVATION) {
85033025f3SGunnar Mills            $interval.cancel(pollActivationTimer);
86033025f3SGunnar Mills            pollActivationTimer = undefined;
87ba5e3f34SAndrew Geissler            console.log('Time out activating image, ' + imageId);
88d27bb135SAndrew Geissler            deferred.reject(
89d27bb135SAndrew Geissler                'Time out. Image did not activate in allotted time.');
90033025f3SGunnar Mills          }
91033025f3SGunnar Mills        }, Constants.POLL_INTERVALS.ACTIVATION);
92033025f3SGunnar Mills        return deferred.promise;
93033025f3SGunnar Mills      }
94033025f3SGunnar Mills
95e7f83970SGunnar Mills      $scope.activateConfirmed = function() {
96d27bb135SAndrew Geissler        APIUtils.activateImage($scope.activate_image_id)
97d27bb135SAndrew Geissler            .then(
98d27bb135SAndrew Geissler                function(state) {
99033025f3SGunnar Mills                  $scope.loadFirmwares();
100033025f3SGunnar Mills                  return state;
101d27bb135SAndrew Geissler                },
102d27bb135SAndrew Geissler                function(error) {
10390ae95ebSbeccabroek                  console.log(JSON.stringify(error));
10427ce84d2Sbeccabroek                  toastService.error('Unable to activate image');
105d27bb135SAndrew Geissler                })
106d27bb135SAndrew Geissler            .then(function(activationState) {
107d27bb135SAndrew Geissler              waitForActive($scope.activate_image_id)
108d27bb135SAndrew Geissler                  .then(
109d27bb135SAndrew Geissler                      function(state) {
1102a489554SIftekharul Islam                        $scope.loadFirmwares();
111d27bb135SAndrew Geissler                      },
112d27bb135SAndrew Geissler                      function(error) {
11390ae95ebSbeccabroek                        console.log(JSON.stringify(error));
11427ce84d2Sbeccabroek                        toastService.error('Unable to activate image');
115d27bb135SAndrew Geissler                      })
116d27bb135SAndrew Geissler                  .then(function(state) {
117d27bb135SAndrew Geissler                    if ($scope.activate.reboot &&
118d27bb135SAndrew Geissler                        ($scope.activate_image_type == 'BMC')) {
119c57ec32fSDixsie Wolmers                      APIUtils.bmcReboot().then(
120c57ec32fSDixsie Wolmers                          function(response) {
121c57ec32fSDixsie Wolmers                            toastService.success('BMC is rebooting.')
122c57ec32fSDixsie Wolmers                          },
123d27bb135SAndrew Geissler                          function(error) {
12490ae95ebSbeccabroek                            console.log(JSON.stringify(error));
125c57ec32fSDixsie Wolmers                            toastService.error('Unable to reboot BMC.');
1266d9ef5acSGunnar Mills                          });
1276d9ef5acSGunnar Mills                    }
128c3abaa9bSbeccabroek                    if ($scope.activate.reboot &&
129c3abaa9bSbeccabroek                        ($scope.activate_image_type == 'Host')) {
130c3abaa9bSbeccabroek                      // If image type being activated is a host image, the
131c3abaa9bSbeccabroek                      // current power status of the server determines if the
132c3abaa9bSbeccabroek                      // server should power on or reboot.
133c3abaa9bSbeccabroek                      if ($scope.isServerOff()) {
134c3abaa9bSbeccabroek                        powerOn();
135c3abaa9bSbeccabroek                      } else {
136c3abaa9bSbeccabroek                        warmReboot();
137c3abaa9bSbeccabroek                      }
138c3abaa9bSbeccabroek                    }
139033025f3SGunnar Mills                  });
1402a489554SIftekharul Islam            });
141e7f83970SGunnar Mills        $scope.activate_confirm = false;
142ba5e3f34SAndrew Geissler      };
143c3abaa9bSbeccabroek      function powerOn() {
144c3abaa9bSbeccabroek        dataService.setUnreachableState();
145c3abaa9bSbeccabroek        APIUtils.hostPowerOn()
146c3abaa9bSbeccabroek            .then(function(response) {
147c3abaa9bSbeccabroek              return response;
148c3abaa9bSbeccabroek            })
149c3abaa9bSbeccabroek            .then(function(lastStatus) {
150c3abaa9bSbeccabroek              return APIUtils.pollHostStatusTillOn();
151c3abaa9bSbeccabroek            })
152c3abaa9bSbeccabroek            .catch(function(error) {
15390ae95ebSbeccabroek              console.log(JSON.stringify(error));
15427ce84d2Sbeccabroek              toastService.error(Constants.MESSAGES.POWER_OP.POWER_ON_FAILED);
155c3abaa9bSbeccabroek            });
156c3abaa9bSbeccabroek      };
157c3abaa9bSbeccabroek      function warmReboot() {
158c3abaa9bSbeccabroek        $scope.uploading = true;
159c3abaa9bSbeccabroek        dataService.setUnreachableState();
160c3abaa9bSbeccabroek        APIUtils.hostReboot()
161c3abaa9bSbeccabroek            .then(function(response) {
162c3abaa9bSbeccabroek              return response;
163c3abaa9bSbeccabroek            })
164c3abaa9bSbeccabroek            .then(function(lastStatus) {
165c3abaa9bSbeccabroek              return APIUtils.pollHostStatusTilReboot();
166c3abaa9bSbeccabroek            })
167c3abaa9bSbeccabroek            .catch(function(error) {
16890ae95ebSbeccabroek              console.log(JSON.stringify(error));
16927ce84d2Sbeccabroek              toastService.error(
17027ce84d2Sbeccabroek                  Constants.MESSAGES.POWER_OP.WARM_REBOOT_FAILED);
171c3abaa9bSbeccabroek            });
172c3abaa9bSbeccabroek      };
173c3abaa9bSbeccabroek      $scope.isServerOff = function() {
174c3abaa9bSbeccabroek        return dataService.server_state === Constants.HOST_STATE_TEXT.off;
175c3abaa9bSbeccabroek      };
176c016139fSIftekharul Islam
177c016139fSIftekharul Islam      $scope.upload = function() {
178dddb1497SGunnar Mills        if ($scope.file) {
179c016139fSIftekharul Islam          $scope.uploading = true;
180d27bb135SAndrew Geissler          APIUtils.uploadImage($scope.file)
181d27bb135SAndrew Geissler              .then(
182d27bb135SAndrew Geissler                  function(response) {
183c016139fSIftekharul Islam                    $scope.uploading = false;
18427ce84d2Sbeccabroek                    toastService.success(
18590ae95ebSbeccabroek                        'Image file "' + $scope.file.name +
18690ae95ebSbeccabroek                        '" has been uploaded');
18790ae95ebSbeccabroek                    $scope.file = '';
188c016139fSIftekharul Islam                    $scope.loadFirmwares();
189d27bb135SAndrew Geissler                  },
190d27bb135SAndrew Geissler                  function(error) {
19187c3db65SGunnar Mills                    $scope.uploading = false;
192f97adb9fSCamVan Nguyen                    console.log(error);
19327ce84d2Sbeccabroek                    toastService.error('Unable to upload image file');
194c016139fSIftekharul Islam                  });
195dddb1497SGunnar Mills        }
196ba5e3f34SAndrew Geissler      };
197c016139fSIftekharul Islam
19858301ec8SCamVan Nguyen      // TODO: openbmc/openbmc#1691 Add support to return
19958301ec8SCamVan Nguyen      // the id of the newly created image, downloaded via
20058301ec8SCamVan Nguyen      // tftp. Polling the number of software objects is a
20158301ec8SCamVan Nguyen      // near term solution.
20258301ec8SCamVan Nguyen      function waitForDownload() {
20358301ec8SCamVan Nguyen        var deferred = $q.defer();
20458301ec8SCamVan Nguyen        var startTime = new Date();
20558301ec8SCamVan Nguyen        pollDownloadTimer = $interval(function() {
20658301ec8SCamVan Nguyen          var now = new Date();
207d27bb135SAndrew Geissler          if ((now.getTime() - startTime.getTime()) >=
208d27bb135SAndrew Geissler              Constants.TIMEOUT.DOWNLOAD_IMAGE) {
20958301ec8SCamVan Nguyen            $interval.cancel(pollDownloadTimer);
21058301ec8SCamVan Nguyen            pollDownloadTimer = undefined;
211d27bb135SAndrew Geissler            deferred.reject(
212d27bb135SAndrew Geissler                new Error(Constants.MESSAGES.POLL.DOWNLOAD_IMAGE_TIMEOUT));
21358301ec8SCamVan Nguyen          }
21458301ec8SCamVan Nguyen
215d27bb135SAndrew Geissler          APIUtils.getFirmwares().then(
216d27bb135SAndrew Geissler              function(response) {
21758301ec8SCamVan Nguyen                if (response.data.length === $scope.firmwares.length + 1) {
21858301ec8SCamVan Nguyen                  $interval.cancel(pollDownloadTimer);
21958301ec8SCamVan Nguyen                  pollDownloadTimer = undefined;
22058301ec8SCamVan Nguyen                  deferred.resolve(response.data);
22158301ec8SCamVan Nguyen                }
222d27bb135SAndrew Geissler              },
223d27bb135SAndrew Geissler              function(error) {
22458301ec8SCamVan Nguyen                $interval.cancel(pollDownloadTimer);
22558301ec8SCamVan Nguyen                pollDownloadTimer = undefined;
22658301ec8SCamVan Nguyen                deferred.reject(error);
22758301ec8SCamVan Nguyen              });
22858301ec8SCamVan Nguyen        }, Constants.POLL_INTERVALS.DOWNLOAD_IMAGE);
22958301ec8SCamVan Nguyen
23058301ec8SCamVan Nguyen        return deferred.promise;
23158301ec8SCamVan Nguyen      }
23258301ec8SCamVan Nguyen
2331acb412dSIftekharul Islam      $scope.download = function() {
2346d7b4a8dSGunnar Mills        if (!$scope.download_host || !$scope.download_filename) {
23527ce84d2Sbeccabroek          toastService.error(
23627ce84d2Sbeccabroek              'TFTP server IP address and file name are required!');
2376d7b4a8dSGunnar Mills          return false;
2386d7b4a8dSGunnar Mills        }
23958301ec8SCamVan Nguyen
2401acb412dSIftekharul Islam        $scope.downloading = true;
241d27bb135SAndrew Geissler        APIUtils.getFirmwares()
242d27bb135SAndrew Geissler            .then(function(response) {
24358301ec8SCamVan Nguyen              $scope.firmwares = response.data;
244d27bb135SAndrew Geissler            })
245d27bb135SAndrew Geissler            .then(function() {
246d27bb135SAndrew Geissler              return APIUtils
247d27bb135SAndrew Geissler                  .downloadImage($scope.download_host, $scope.download_filename)
248d27bb135SAndrew Geissler                  .then(function(downloadStatus) {
24958301ec8SCamVan Nguyen                    return downloadStatus;
25058301ec8SCamVan Nguyen                  });
251d27bb135SAndrew Geissler            })
252d27bb135SAndrew Geissler            .then(function(downloadStatus) {
25358301ec8SCamVan Nguyen              return waitForDownload();
254d27bb135SAndrew Geissler            })
255d27bb135SAndrew Geissler            .then(
256d27bb135SAndrew Geissler                function(newFirmwareList) {
257ba5e3f34SAndrew Geissler                  $scope.download_host = '';
258ba5e3f34SAndrew Geissler                  $scope.download_filename = '';
2591acb412dSIftekharul Islam                  $scope.downloading = false;
26027ce84d2Sbeccabroek                  toastService.success('Download complete');
26158301ec8SCamVan Nguyen                  $scope.loadFirmwares();
262d27bb135SAndrew Geissler                },
263d27bb135SAndrew Geissler                function(error) {
26458301ec8SCamVan Nguyen                  console.log(error);
26527ce84d2Sbeccabroek                  toastService.error(
26690ae95ebSbeccabroek                      'Image file from TFTP server "' + $scope.download_host +
26790ae95ebSbeccabroek                      '" could not be downloaded');
26858301ec8SCamVan Nguyen                  $scope.downloading = false;
2691acb412dSIftekharul Islam                });
270ba5e3f34SAndrew Geissler      };
2711acb412dSIftekharul Islam
2726473a41dSGunnar Mills      $scope.changePriority = function(imageId, imageVersion, from, to) {
2731acb412dSIftekharul Islam        $scope.priority_image_id = imageId;
2746473a41dSGunnar Mills        $scope.priority_image_version = imageVersion;
2751acb412dSIftekharul Islam        $scope.priority_from = from;
2761acb412dSIftekharul Islam        $scope.priority_to = to;
2771acb412dSIftekharul Islam        $scope.confirm_priority = true;
278ba5e3f34SAndrew Geissler      };
2791acb412dSIftekharul Islam
2801acb412dSIftekharul Islam      $scope.confirmChangePriority = function() {
2811acb412dSIftekharul Islam        $scope.loading = true;
282d27bb135SAndrew Geissler        APIUtils.changePriority($scope.priority_image_id, $scope.priority_to)
283d27bb135SAndrew Geissler            .then(function(response) {
2841acb412dSIftekharul Islam              $scope.loading = false;
2851acb412dSIftekharul Islam              if (response.status == 'error') {
28627ce84d2Sbeccabroek                toastService.error('Unable to update boot priority');
287d27bb135SAndrew Geissler              } else {
2881acb412dSIftekharul Islam                $scope.loadFirmwares();
2891acb412dSIftekharul Islam              }
2901acb412dSIftekharul Islam            });
2911acb412dSIftekharul Islam        $scope.confirm_priority = false;
292ba5e3f34SAndrew Geissler      };
293607a120aSGunnar Mills      $scope.deleteImage = function(imageId, imageVersion) {
294c016139fSIftekharul Islam        $scope.delete_image_id = imageId;
295607a120aSGunnar Mills        $scope.delete_image_version = imageVersion;
296c016139fSIftekharul Islam        $scope.confirm_delete = true;
297ba5e3f34SAndrew Geissler      };
2982a489554SIftekharul Islam      $scope.confirmDeleteImage = function() {
2992a489554SIftekharul Islam        $scope.loading = true;
3002a489554SIftekharul Islam        APIUtils.deleteImage($scope.delete_image_id).then(function(response) {
3012a489554SIftekharul Islam          $scope.loading = false;
3022a489554SIftekharul Islam          if (response.status == 'error') {
30327ce84d2Sbeccabroek            toastService.error('Unable to delete image');
304d27bb135SAndrew Geissler          } else {
3052a489554SIftekharul Islam            $scope.loadFirmwares();
3062a489554SIftekharul Islam          }
3072a489554SIftekharul Islam        });
308c016139fSIftekharul Islam        $scope.confirm_delete = false;
309ba5e3f34SAndrew Geissler      };
310c016139fSIftekharul Islam
311d27bb135SAndrew Geissler      $scope.filters = {bmc: {imageType: 'BMC'}, host: {imageType: 'Host'}};
312c016139fSIftekharul Islam
313c016139fSIftekharul Islam      $scope.loadFirmwares = function() {
314df3bd124SMichael Davis        APIUtils.getFirmwares().then(function(result) {
315df3bd124SMichael Davis          $scope.firmwares = result.data;
316df3bd124SMichael Davis          $scope.bmcActiveVersion = result.bmcActiveVersion;
317df3bd124SMichael Davis          $scope.hostActiveVersion = result.hostActiveVersion;
318c016139fSIftekharul Islam        });
319ba5e3f34SAndrew Geissler      };
320c016139fSIftekharul Islam
321c016139fSIftekharul Islam      $scope.loadFirmwares();
32243366db7SMichael Davis    }
323ba5e3f34SAndrew Geissler  ]);
32443366db7SMichael Davis})(angular);
325