blob: 04ab3e829337f4d347a6c703c6fd243f301d9e3b [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
65 this.getStats = (sliceName) => {
66 let deferred = $q.defer();
67
68 $http.get('/xoslib/meterstatistics/', {cache: true})
69 // $http.get('../stats_mock.son', {cache: true})
70 .then((res) => {
71 deferred.resolve(lodash.filter(res.data, {slice: sliceName}))
72 })
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: {}
Matteo Scandolobb06c532016-01-28 14:50:16 -080097 };
Matteo Scandolo6c6b9282015-12-15 14:37:27 -080098
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 Scandolo68856082015-12-08 14:35:55 -0800154 //cleaning
155 this.selectedResources = null;
156 this.selectedResource = null;
157 this.selectedMeters = null;
158
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800159 // hold the resource list for the current slice
Matteo Scandolo68856082015-12-08 14:35:55 -0800160 this.selectedResources = resources;
161 this.selectedSlice = slice;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800162 this.selectedService = service;
163
164 // store the status
165 Ceilometer.selectedSlice = slice;
166 Ceilometer.selectedService = service;
Matteo Scandolo68856082015-12-08 14:35:55 -0800167 }
168
169 /**
170 * Select Meters for a resource
171 *
172 * @param Array meters The list of selected resources
173 * @returns void
174 */
175 this.selectedMeters = null;
176 this.selectMeters = (meters, resource) => {
177 this.selectedMeters = meters;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800178
179 Ceilometer.selectedResource = resource;
Matteo Scandolo68856082015-12-08 14:35:55 -0800180 this.selectedResource = resource;
181 }
182
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800183 }
184 };
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800185})
186.directive('ceilometerSamples', function(lodash, $stateParams){
187 return {
188 restrict: 'E',
189 scope: {
190 name: '=name',
191 tenant: '=tenant'
192 },
193 bindToController: true,
194 controllerAs: 'vm',
195 templateUrl: 'templates/ceilometer-samples.tpl.html',
196 controller: function(Ceilometer) {
197
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800198 // console.log(Ceilometer.selectResource);
199
Matteo Scandolo324df092015-12-08 16:39:57 -0800200 this.chartColors = [
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800201 '#286090',
202 '#F7464A',
203 '#46BFBD',
204 '#FDB45C',
205 '#97BBCD',
206 '#4D5360',
207 '#8c4f9f'
208 ];
Matteo Scandolo324df092015-12-08 16:39:57 -0800209
210 this.chart = {
211 series: [],
212 labels: [],
213 data: []
214 }
215
216 Chart.defaults.global.colours = this.chartColors;
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800217
Matteo Scandolo68856082015-12-08 14:35:55 -0800218 this.chartType = 'line';
219
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800220 if($stateParams.name && $stateParams.tenant){
221 this.name = $stateParams.name;
222 this.tenant = $stateParams.tenant;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800223 // TODO rename tenant in project_id
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800224 }
Matteo Scandolo1b9ffac2015-12-14 17:36:09 -0800225 else{
226 throw new Error('Missing Name and Tenant Params!');
227 }
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800228
Matteo Scandolo68856082015-12-08 14:35:55 -0800229 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800230 * Goes trough the array and format date to be used as labels
Matteo Scandolo68856082015-12-08 14:35:55 -0800231 *
232 * @param Array data
233 * @returns Array a list of labels
234 */
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800235
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800236 this.getLabels = (data) => {
237 return data.reduce((list, item) => {
238 let date = new Date(item.timestamp);
239 list.push(`${date.getHours()}:${(date.getMinutes()<10?'0':'') + date.getMinutes()}:${date.getSeconds()}`);
240 return list;
241 }, []);
242 };
243
Matteo Scandolo68856082015-12-08 14:35:55 -0800244 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800245 * Goes trough the array and return a flat array of values
Matteo Scandolo68856082015-12-08 14:35:55 -0800246 *
247 * @param Array data
248 * @returns Array a list of values
249 */
250
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800251 this.getData = (data) => {
252 return data.reduce((list, item) => {
253 list.push(item.volume);
254 return list;
255 }, []);
256 }
257
Matteo Scandolo324df092015-12-08 16:39:57 -0800258 /**
259 * Add a samples to the chart
260 *
261 * @param string resource_id
262 */
263 this.chartMeters = [];
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800264 this.addMeterToChart = (project_id) => {
265 this.chart['labels'] = this.getLabels(lodash.sortBy(this.samplesList[project_id], 'timestamp'));
266 this.chart['series'].push(project_id);
267 this.chart['data'].push(this.getData(lodash.sortBy(this.samplesList[project_id], 'timestamp')));
268 this.chartMeters.push(this.samplesList[project_id][0]); //use the 0 as are all samples for the same resource and I need the name
269 lodash.remove(this.sampleLabels, {id: project_id});
Matteo Scandolo68856082015-12-08 14:35:55 -0800270 }
271
Matteo Scandoloe5d5ebd2015-12-14 14:42:28 -0800272 this.removeFromChart = (meter) => {
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800273 this.chart.data.splice(this.chart.series.indexOf(meter.project_id), 1);
274 this.chart.series.splice(this.chart.series.indexOf(meter.project_id), 1);
275 this.chartMeters.splice(lodash.findIndex(this.chartMeters, {project_id: meter.project_id}), 1);
Matteo Scandolo324df092015-12-08 16:39:57 -0800276 this.sampleLabels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800277 id: meter.project_id,
278 name: meter.resource_name || meter.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800279 })
280 };
281
282 /**
283 * Format samples to create a list of labels and ids
284 */
285
286 this.formatSamplesLabels = (samples) => {
287
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800288 return lodash.uniq(samples, 'project_id')
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800289 .reduce((labels, item) => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800290 labels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800291 id: item.project_id,
292 name: item.resource_name || item.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800293 });
294 return labels;
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800295 }, []);
Matteo Scandolo324df092015-12-08 16:39:57 -0800296 }
297
298
Matteo Scandolo68856082015-12-08 14:35:55 -0800299 /**
300 * Load the samples and format data
301 */
302
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800303 this.showSamples = () => {
304 this.loader = true;
Matteo Scandolo68856082015-12-08 14:35:55 -0800305 // Ceilometer.getSamples(this.name, this.tenant) //fetch one
306 Ceilometer.getSamples(this.name) //fetch all
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800307 .then(res => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800308
309 // setup data for visualization
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800310 this.samplesList = lodash.groupBy(res, 'project_id');
Matteo Scandolo324df092015-12-08 16:39:57 -0800311 this.sampleLabels = this.formatSamplesLabels(res);
312
313 // add current meter to chart
314 this.addMeterToChart(this.tenant);
315
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800316 })
317 .catch(err => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800318 this.error = err.data.detail;
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800319 })
320 .finally(() => {
321 this.loader = false;
322 });
323 };
324
325 this.showSamples();
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800326 }
327 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800328})
Matteo Scandolobb06c532016-01-28 14:50:16 -0800329 // NOTE reading this on demand for a single
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800330.directive('ceilometerStats', function(){
331 return {
332 restrict: 'E',
333 scope: {
334 name: '=name',
335 },
336 bindToController: true,
337 controllerAs: 'vm',
338 templateUrl: 'templates/ceilometer-stats.tpl.html',
339 controller: function($scope, Ceilometer) {
340 this.getStats = () => {
341 this.loader = true;
342 Ceilometer.getStats(this.name)
343 .then(res => {
344 this.stats = res;
345 })
346 .catch(err => {
347 this.error = err.data;
348 })
349 .finally(() => {
350 this.loader = false;
351 });
352 };
353
354 this.getStats();
355
356 $scope.$watch(() => this.name, () => {this.getStats();});
357 }
358 }
Matteo Scandolo869acc52015-12-10 10:15:20 -0800359})
360.filter('orderObjectByKey', function(lodash) {
Matteo Scandolo83869332015-12-14 14:26:20 -0800361 return function(items) {
Matteo Scandolo869acc52015-12-10 10:15:20 -0800362
363 if(!items){
364 return;
365 }
366
367 return lodash.reduce(Object.keys(items).reverse(), (list, key) => {
368 list[key] = items[key];
369 return list;
370 }, {});
371
372 };
373});
374;