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