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