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