blob: 01b9adce43ebe25b707e5fde759b4c5af5ac7429 [file] [log] [blame]
Matteo Scandolo68c2e722015-12-04 10:14:40 -08001'use strict';
2
3angular.module('xos.ceilometerDashboard', [
4 'ngResource',
5 'ngCookies',
6 'ngLodash',
7 'ui.router',
8 'xos.helpers',
Matteo Scandolo68856082015-12-08 14:35:55 -08009 'ngAnimate',
Matteo Scandoloc0582112015-12-09 16:09:59 -080010 'chart.js',
11 'ui.bootstrap.accordion'
Matteo Scandolo68c2e722015-12-04 10:14:40 -080012])
Matteo Scandolo68856082015-12-08 14:35:55 -080013.config(($stateProvider, $urlRouterProvider) => {
Matteo Scandolo68c2e722015-12-04 10:14:40 -080014 $stateProvider
15 .state('ceilometerDashboard', {
16 url: '/',
17 template: '<ceilometer-dashboard></ceilometer-dashboard>'
Matteo Scandolo7b80d842015-12-04 15:55:20 -080018 })
19 .state('samples', {
20 url: '/:name/:tenant/samples',
21 template: '<ceilometer-samples></ceilometer-samples>'
Matteo Scandolo68c2e722015-12-04 10:14:40 -080022 });
Matteo Scandolo68856082015-12-08 14:35:55 -080023 $urlRouterProvider.otherwise('/');
Matteo Scandolo68c2e722015-12-04 10:14:40 -080024})
25.config(function($httpProvider){
26 $httpProvider.interceptors.push('NoHyperlinks');
27})
Matteo Scandolo68856082015-12-08 14:35:55 -080028.run(function($rootScope){
29 $rootScope.stateName = 'ceilometerDashboard';
30 $rootScope.$on('$stateChangeStart', (event, toState) => {
Matteo Scandolo68856082015-12-08 14:35:55 -080031 $rootScope.stateName = toState.name;
32 })
33})
Matteo Scandolo41f5c152015-12-09 17:09:55 -080034.service('Ceilometer', function($http, $q, lodash){
Matteo Scandolo2b6583e2015-12-08 15:24:23 -080035
Matteo Scandolo68c2e722015-12-04 10:14:40 -080036 this.getMeters = () => {
37 let deferred = $q.defer();
38
Matteo Scandolo41f5c152015-12-09 17:09:55 -080039 $http.get('/xoslib/meters/', {cache: true})
40 // $http.get('../meters_mock.json', {cache: true})
Matteo Scandolo68c2e722015-12-04 10:14:40 -080041 .then((res) => {
Matteo Scandolo7b80d842015-12-04 15:55:20 -080042 deferred.resolve(res.data)
43 })
44 .catch((e) => {
45 deferred.reject(e);
46 });
47
48 return deferred.promise;
49 }
50
51 this.getSamples = (name, tenant) => {
52 let deferred = $q.defer();
53
Matteo Scandoloac812bd2015-12-07 17:32:39 -080054 $http.get(`/xoslib/metersamples/`, {params: {meter: name, tenant: tenant}})
Matteo Scandolo7b80d842015-12-04 15:55:20 -080055 .then((res) => {
56 deferred.resolve(res.data)
Matteo Scandolo68c2e722015-12-04 10:14:40 -080057 })
58 .catch((e) => {
59 deferred.reject(e);
60 });
61
62 return deferred.promise;
63 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -080064
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -080065 this.getStats = (options) => {
Matteo Scandolo41f5c152015-12-09 17:09:55 -080066 let deferred = $q.defer();
67
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -080068 $http.get('/xoslib/meterstatistics/', {cache: true, params: options})
Matteo Scandolo41f5c152015-12-09 17:09:55 -080069 // $http.get('../stats_mock.son', {cache: true})
70 .then((res) => {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -080071 deferred.resolve(res.data);
Matteo Scandolo41f5c152015-12-09 17:09:55 -080072 })
73 .catch((e) => {
74 deferred.reject(e);
75 });
76
77 return deferred.promise;
78 };
Matteo Scandolo6c6b9282015-12-15 14:37:27 -080079
80 // hold dashboard status (opened service, slice, resource)
81 this.selectedService = null;
82 this.selectedSlice = null;
83 this.selectedResource = null;
Matteo Scandolo68c2e722015-12-04 10:14:40 -080084})
Matteo Scandolo7b80d842015-12-04 15:55:20 -080085.directive('ceilometerDashboard', function(lodash){
Matteo Scandolo68c2e722015-12-04 10:14:40 -080086 return {
87 restrict: 'E',
88 scope: {},
89 bindToController: true,
90 controllerAs: 'vm',
91 templateUrl: 'templates/ceilometer-dashboard.tpl.html',
92 controller: function(Ceilometer){
93
Matteo Scandolo6c6b9282015-12-15 14:37:27 -080094 // this open the accordion
95 this.accordion = {
96 open: {}
97 }
98
99 /**
100 * Open the active panel base on the service stored values
101 */
102 this.openPanels = () => {
103 if(Ceilometer.selectedService){
104 this.accordion.open[Ceilometer.selectedService] = true;
105 if(Ceilometer.selectedSlice){
106 this.selectedSlice = Ceilometer.selectedSlice;
107 this.selectedResources = this.projects[Ceilometer.selectedService][Ceilometer.selectedSlice]
108 if(Ceilometer.selectedResource){
109 this.selectedResource = Ceilometer.selectedResource;
110 this.selectedMeters = this.selectedResources[Ceilometer.selectedResource];
111 }
112 }
113 }
114 }
115
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800116 this.loadMeters = () => {
117 this.loader = true;
118
Matteo Scandolo1b9ffac2015-12-14 17:36:09 -0800119 // TODO rename projects in meters
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800120 Ceilometer.getMeters()
121 .then(meters => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800122 //group project by service
123 this.projects = lodash.groupBy(meters, 'service');
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800124 lodash.forEach(Object.keys(this.projects), (project) => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800125 // inside each service group by slice
126 this.projects[project] = lodash.groupBy(this.projects[project], 'slice');
127 lodash.forEach(Object.keys(this.projects[project]), (slice) => {
128 // inside each service => slice group by resource
Matteo Scandolo83869332015-12-14 14:26:20 -0800129 this.projects[project][slice] = lodash.groupBy(this.projects[project][slice], 'resource_name');
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800130 });
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800131 });
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800132
133 // open selected panels
134 this.openPanels();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800135 })
136 .catch(err => {
Matteo Scandolo83869332015-12-14 14:26:20 -0800137 this.error = err.data.detail;
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800138 })
139 .finally(() => {
140 this.loader = false;
141 });
142 }
143
144 this.loadMeters();
145
Matteo Scandolo68856082015-12-08 14:35:55 -0800146 /**
147 * Select Resources for a slice
148 *
149 * @param Array resources The list of selected resources
150 * @returns void
151 */
152 this.selectedResources = null;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800153 this.selectResources = (resources, slice, service) => {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800154
Matteo Scandolo68856082015-12-08 14:35:55 -0800155 //cleaning
156 this.selectedResources = null;
157 this.selectedResource = null;
158 this.selectedMeters = null;
159
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800160 // hold the resource list for the current slice
Matteo Scandolo68856082015-12-08 14:35:55 -0800161 this.selectedResources = resources;
162 this.selectedSlice = slice;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800163 this.selectedService = service;
164
165 // store the status
166 Ceilometer.selectedSlice = slice;
167 Ceilometer.selectedService = service;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800168
169 // store tenant (slice id for ceilometer)
170 // it is passed to ceilometer-stats directive
171 console.log(resources);
172 this.selectedTenant = resources[Object.keys(resources)[0]][0].project_id;
Matteo Scandolo68856082015-12-08 14:35:55 -0800173 }
174
175 /**
176 * Select Meters for a resource
177 *
178 * @param Array meters The list of selected resources
179 * @returns void
180 */
181 this.selectedMeters = null;
182 this.selectMeters = (meters, resource) => {
183 this.selectedMeters = meters;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800184
185 Ceilometer.selectedResource = resource;
Matteo Scandolo68856082015-12-08 14:35:55 -0800186 this.selectedResource = resource;
187 }
188
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800189 }
190 };
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800191})
192.directive('ceilometerSamples', function(lodash, $stateParams){
193 return {
194 restrict: 'E',
Matteo Scandolo895b30a2016-02-02 16:04:31 -0800195 scope: {},
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800196 bindToController: true,
197 controllerAs: 'vm',
198 templateUrl: 'templates/ceilometer-samples.tpl.html',
199 controller: function(Ceilometer) {
200
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800201 // console.log(Ceilometer.selectResource);
202
Matteo Scandolo324df092015-12-08 16:39:57 -0800203 this.chartColors = [
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800204 '#286090',
205 '#F7464A',
206 '#46BFBD',
207 '#FDB45C',
208 '#97BBCD',
209 '#4D5360',
210 '#8c4f9f'
211 ];
Matteo Scandolo324df092015-12-08 16:39:57 -0800212
213 this.chart = {
214 series: [],
215 labels: [],
216 data: []
217 }
218
219 Chart.defaults.global.colours = this.chartColors;
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800220
Matteo Scandolo68856082015-12-08 14:35:55 -0800221 this.chartType = 'line';
222
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800223 if($stateParams.name && $stateParams.tenant){
224 this.name = $stateParams.name;
225 this.tenant = $stateParams.tenant;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800226 // TODO rename tenant in project_id
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800227 }
Matteo Scandolo1b9ffac2015-12-14 17:36:09 -0800228 else{
229 throw new Error('Missing Name and Tenant Params!');
230 }
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800231
Matteo Scandolo68856082015-12-08 14:35:55 -0800232 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800233 * Goes trough the array and format date to be used as labels
Matteo Scandolo68856082015-12-08 14:35:55 -0800234 *
235 * @param Array data
236 * @returns Array a list of labels
237 */
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800238
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800239 this.getLabels = (data) => {
240 return data.reduce((list, item) => {
241 let date = new Date(item.timestamp);
242 list.push(`${date.getHours()}:${(date.getMinutes()<10?'0':'') + date.getMinutes()}:${date.getSeconds()}`);
243 return list;
244 }, []);
245 };
246
Matteo Scandolo68856082015-12-08 14:35:55 -0800247 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800248 * Goes trough the array and return a flat array of values
Matteo Scandolo68856082015-12-08 14:35:55 -0800249 *
250 * @param Array data
251 * @returns Array a list of values
252 */
253
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800254 this.getData = (data) => {
255 return data.reduce((list, item) => {
256 list.push(item.volume);
257 return list;
258 }, []);
259 }
260
Matteo Scandolo324df092015-12-08 16:39:57 -0800261 /**
262 * Add a samples to the chart
263 *
264 * @param string resource_id
265 */
266 this.chartMeters = [];
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800267 this.addMeterToChart = (project_id) => {
268 this.chart['labels'] = this.getLabels(lodash.sortBy(this.samplesList[project_id], 'timestamp'));
269 this.chart['series'].push(project_id);
270 this.chart['data'].push(this.getData(lodash.sortBy(this.samplesList[project_id], 'timestamp')));
271 this.chartMeters.push(this.samplesList[project_id][0]); //use the 0 as are all samples for the same resource and I need the name
272 lodash.remove(this.sampleLabels, {id: project_id});
Matteo Scandolo68856082015-12-08 14:35:55 -0800273 }
274
Matteo Scandoloe5d5ebd2015-12-14 14:42:28 -0800275 this.removeFromChart = (meter) => {
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800276 this.chart.data.splice(this.chart.series.indexOf(meter.project_id), 1);
277 this.chart.series.splice(this.chart.series.indexOf(meter.project_id), 1);
278 this.chartMeters.splice(lodash.findIndex(this.chartMeters, {project_id: meter.project_id}), 1);
Matteo Scandolo324df092015-12-08 16:39:57 -0800279 this.sampleLabels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800280 id: meter.project_id,
281 name: meter.resource_name || meter.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800282 })
283 };
284
285 /**
286 * Format samples to create a list of labels and ids
287 */
288
289 this.formatSamplesLabels = (samples) => {
290
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800291 return lodash.uniq(samples, 'project_id')
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800292 .reduce((labels, item) => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800293 labels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800294 id: item.project_id,
295 name: item.resource_name || item.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800296 });
297 return labels;
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800298 }, []);
Matteo Scandolo324df092015-12-08 16:39:57 -0800299 }
300
301
Matteo Scandolo68856082015-12-08 14:35:55 -0800302 /**
303 * Load the samples and format data
304 */
305
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800306 this.showSamples = () => {
307 this.loader = true;
Matteo Scandolo68856082015-12-08 14:35:55 -0800308 // Ceilometer.getSamples(this.name, this.tenant) //fetch one
309 Ceilometer.getSamples(this.name) //fetch all
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800310 .then(res => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800311
312 // setup data for visualization
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800313 this.samplesList = lodash.groupBy(res, 'project_id');
Matteo Scandolo324df092015-12-08 16:39:57 -0800314 this.sampleLabels = this.formatSamplesLabels(res);
315
316 // add current meter to chart
317 this.addMeterToChart(this.tenant);
318
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800319 })
320 .catch(err => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800321 this.error = err.data.detail;
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800322 })
323 .finally(() => {
324 this.loader = false;
325 });
326 };
327
328 this.showSamples();
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800329 }
330 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800331})
332.directive('ceilometerStats', function(){
333 return {
334 restrict: 'E',
335 scope: {
336 name: '=name',
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800337 tenant: '=tenant'
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800338 },
339 bindToController: true,
340 controllerAs: 'vm',
341 templateUrl: 'templates/ceilometer-stats.tpl.html',
342 controller: function($scope, Ceilometer) {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800343
344 this.getStats = (tenant) => {
345 console.log(this.tenant);
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800346 this.loader = true;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800347 Ceilometer.getStats({tenant: tenant})
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800348 .then(res => {
349 this.stats = res;
350 })
351 .catch(err => {
352 this.error = err.data;
353 })
354 .finally(() => {
355 this.loader = false;
356 });
357 };
358
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800359 $scope.$watch(() => this.name, (val) => {
360 if(val){
361 this.getStats(this.tenant);
362 }
363 });
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800364 }
365 }
Matteo Scandolo869acc52015-12-10 10:15:20 -0800366})
367.filter('orderObjectByKey', function(lodash) {
Matteo Scandolo83869332015-12-14 14:26:20 -0800368 return function(items) {
Matteo Scandolo869acc52015-12-10 10:15:20 -0800369
370 if(!items){
371 return;
372 }
373
374 return lodash.reduce(Object.keys(items).reverse(), (list, key) => {
375 list[key] = items[key];
376 return list;
377 }, {});
378
379 };
380});
381;