blob: 27312cee96795f8eb77f54334953afe3a7197088 [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 Scandoloba4c9aa2016-02-11 09:35:29 -080034.service('Ceilometer', function($http, $q){
Matteo Scandolo2b6583e2015-12-08 15:24:23 -080035
Matteo Scandolo9db064f2016-02-08 14:17:42 -080036 this.getMappings = () => {
Matteo Scandolo68c2e722015-12-04 10:14:40 -080037 let deferred = $q.defer();
38
Matteo Scandolo9db064f2016-02-08 14:17:42 -080039 $http.get('/xoslib/xos-slice-service-mapping/')
40 .then((res) => {
41 deferred.resolve(res.data)
42 })
43 .catch((e) => {
44 deferred.reject(e);
45 });
46
47 return deferred.promise;
48 }
49
50 this.getMeters = (params) => {
51 let deferred = $q.defer();
52
53 $http.get('/xoslib/meters/', {cache: true, params: params})
Matteo Scandolo41f5c152015-12-09 17:09:55 -080054 // $http.get('../meters_mock.json', {cache: true})
Matteo Scandolo68c2e722015-12-04 10:14:40 -080055 .then((res) => {
Matteo Scandolo7b80d842015-12-04 15:55:20 -080056 deferred.resolve(res.data)
57 })
58 .catch((e) => {
59 deferred.reject(e);
60 });
61
62 return deferred.promise;
63 }
64
65 this.getSamples = (name, tenant) => {
66 let deferred = $q.defer();
67
Matteo Scandoloac812bd2015-12-07 17:32:39 -080068 $http.get(`/xoslib/metersamples/`, {params: {meter: name, tenant: tenant}})
Matteo Scandolo7b80d842015-12-04 15:55:20 -080069 .then((res) => {
70 deferred.resolve(res.data)
Matteo Scandolo68c2e722015-12-04 10:14:40 -080071 })
72 .catch((e) => {
73 deferred.reject(e);
74 });
75
76 return deferred.promise;
77 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -080078
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -080079 this.getStats = (options) => {
Matteo Scandolo41f5c152015-12-09 17:09:55 -080080 let deferred = $q.defer();
81
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -080082 $http.get('/xoslib/meterstatistics/', {cache: true, params: options})
Matteo Scandolo41f5c152015-12-09 17:09:55 -080083 // $http.get('../stats_mock.son', {cache: true})
84 .then((res) => {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -080085 deferred.resolve(res.data);
Matteo Scandolo41f5c152015-12-09 17:09:55 -080086 })
87 .catch((e) => {
88 deferred.reject(e);
89 });
90
91 return deferred.promise;
92 };
Matteo Scandolo6c6b9282015-12-15 14:37:27 -080093
94 // hold dashboard status (opened service, slice, resource)
95 this.selectedService = null;
96 this.selectedSlice = null;
97 this.selectedResource = null;
Matteo Scandolo68c2e722015-12-04 10:14:40 -080098})
Matteo Scandolo7b80d842015-12-04 15:55:20 -080099.directive('ceilometerDashboard', function(lodash){
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800100 return {
101 restrict: 'E',
102 scope: {},
103 bindToController: true,
104 controllerAs: 'vm',
105 templateUrl: 'templates/ceilometer-dashboard.tpl.html',
106 controller: function(Ceilometer){
107
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800108 this.showStats = false;
109
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800110 // this open the accordion
111 this.accordion = {
112 open: {}
Matteo Scandolobb06c532016-01-28 14:50:16 -0800113 };
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800114
115 /**
116 * Open the active panel base on the service stored values
117 */
118 this.openPanels = () => {
119 if(Ceilometer.selectedService){
120 this.accordion.open[Ceilometer.selectedService] = true;
121 if(Ceilometer.selectedSlice){
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800122 this.loadSliceMeter(Ceilometer.selectedSlice, Ceilometer.selectedService);
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800123 this.selectedSlice = Ceilometer.selectedSlice;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800124 if(Ceilometer.selectedResource){
125 this.selectedResource = Ceilometer.selectedResource;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800126 }
127 }
128 }
129 }
130
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800131 /**
132 * Load the list of service and slices
133 */
134
135 this.loadMappings = () => {
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800136 this.loader = true;
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800137 Ceilometer.getMappings()
138 .then((services) => {
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800139
140 // rename thing in UI
141 services.map((service) => {
142 if(service.service === 'service_ONOS_vBNG'){
143 service.service = 'ONOS_FABRIC';
144 service.slices.map(s => {
145 if(s.slice === 'mysite_onos_vbng'){
146 s.slice = 'ONOS_FABRIC';
147 }
148 });
149 }
150 if(service.service === 'service_ONOS_vOLT'){
151 service.service = 'ONOS_CORD';
152 service.slices.map(s => {
153 if(s.slice === 'mysite_onos_volt'){
154 s.slice = 'ONOS_CORD';
155 }
156 });
157 }
158
159 return service;
160 });
161 // end rename thing in UI
162
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800163 this.services = services;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800164 this.openPanels();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800165 })
166 .catch(err => {
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800167 this.error = (err.data && err.data.detail) ? err.data.detail : 'An Error occurred. Please try again later.';
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800168 })
169 .finally(() => {
170 this.loader = false;
171 });
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800172 };
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800173
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800174 this.loadMappings();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800175
Matteo Scandolo68856082015-12-08 14:35:55 -0800176 /**
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800177 * Load the list of a single slice
Matteo Scandolo68856082015-12-08 14:35:55 -0800178 */
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800179
180 this.loadSliceMeter = (slice, service_name) => {
Matteo Scandolo68856082015-12-08 14:35:55 -0800181
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800182 Ceilometer.selectedSlice = null;
183 Ceilometer.selectedService = null;
184 Ceilometer.selectedResources = null;
Matteo Scandolo68856082015-12-08 14:35:55 -0800185
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800186 // visualization info
187 this.loader = true;
Matteo Scandoloba4c9aa2016-02-11 09:35:29 -0800188 this.error = null;
189 this.ceilometerError = null;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800190
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800191 Ceilometer.getMeters({tenant: slice.project_id})
192 .then((sliceMeters) => {
Matteo Scandoloba4c9aa2016-02-11 09:35:29 -0800193 this.selectedSlice = slice.slice;
194 this.selectedTenant = slice.project_id;
195
196 // store the status
197 Ceilometer.selectedSlice = slice;
198 Ceilometer.selectedService = service_name;
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800199
200 // rename things in UI
201 sliceMeters.map(m => {
202 m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
203 m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
204 return m;
205 });
206 // end rename things in UI
207
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800208 this.selectedResources = lodash.groupBy(sliceMeters, 'resource_name');
209
210 // hacky
211 if(Ceilometer.selectedResource){
212 this.selectedMeters = this.selectedResources[Ceilometer.selectedResource];
213 }
214 })
215 .catch(err => {
Matteo Scandoloba4c9aa2016-02-11 09:35:29 -0800216
217 // this means that ceilometer is not yet ready
218 if(err.status === 503){
219 return this.ceilometerError = err.data.detail.specific_error;
220 }
221
Matteo Scandolo81cfbf72016-02-11 09:49:34 -0800222 this.error = (err.data && err.data.detail.specific_error) ? err.data.detail.specific_error : 'An Error occurred. Please try again later.';
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800223 })
224 .finally(() => {
225 this.loader = false;
226 });
227 };
Matteo Scandolo68856082015-12-08 14:35:55 -0800228
229 /**
230 * Select Meters for a resource
231 *
232 * @param Array meters The list of selected resources
233 * @returns void
234 */
235 this.selectedMeters = null;
236 this.selectMeters = (meters, resource) => {
237 this.selectedMeters = meters;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800238
239 Ceilometer.selectedResource = resource;
Matteo Scandolo68856082015-12-08 14:35:55 -0800240 this.selectedResource = resource;
241 }
242
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800243 }
244 };
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800245})
246.directive('ceilometerSamples', function(lodash, $stateParams){
247 return {
248 restrict: 'E',
Matteo Scandolo895b30a2016-02-02 16:04:31 -0800249 scope: {},
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800250 bindToController: true,
251 controllerAs: 'vm',
252 templateUrl: 'templates/ceilometer-samples.tpl.html',
253 controller: function(Ceilometer) {
254
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800255 // console.log(Ceilometer.selectResource);
256
Matteo Scandolo324df092015-12-08 16:39:57 -0800257 this.chartColors = [
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800258 '#286090',
259 '#F7464A',
260 '#46BFBD',
261 '#FDB45C',
262 '#97BBCD',
263 '#4D5360',
264 '#8c4f9f'
265 ];
Matteo Scandolo324df092015-12-08 16:39:57 -0800266
267 this.chart = {
268 series: [],
269 labels: [],
270 data: []
271 }
272
273 Chart.defaults.global.colours = this.chartColors;
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800274
Matteo Scandolo68856082015-12-08 14:35:55 -0800275 this.chartType = 'line';
276
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800277 if($stateParams.name && $stateParams.tenant){
278 this.name = $stateParams.name;
279 this.tenant = $stateParams.tenant;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800280 // TODO rename tenant in project_id
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800281 }
Matteo Scandolo1b9ffac2015-12-14 17:36:09 -0800282 else{
283 throw new Error('Missing Name and Tenant Params!');
284 }
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800285
Matteo Scandolo68856082015-12-08 14:35:55 -0800286 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800287 * Goes trough the array and format date to be used as labels
Matteo Scandolo68856082015-12-08 14:35:55 -0800288 *
289 * @param Array data
290 * @returns Array a list of labels
291 */
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800292
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800293 this.getLabels = (data) => {
294 return data.reduce((list, item) => {
295 let date = new Date(item.timestamp);
296 list.push(`${date.getHours()}:${(date.getMinutes()<10?'0':'') + date.getMinutes()}:${date.getSeconds()}`);
297 return list;
298 }, []);
299 };
300
Matteo Scandolo68856082015-12-08 14:35:55 -0800301 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800302 * Goes trough the array and return a flat array of values
Matteo Scandolo68856082015-12-08 14:35:55 -0800303 *
304 * @param Array data
305 * @returns Array a list of values
306 */
307
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800308 this.getData = (data) => {
309 return data.reduce((list, item) => {
310 list.push(item.volume);
311 return list;
312 }, []);
313 }
314
Matteo Scandolo324df092015-12-08 16:39:57 -0800315 /**
316 * Add a samples to the chart
317 *
318 * @param string resource_id
319 */
320 this.chartMeters = [];
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800321 this.addMeterToChart = (project_id) => {
322 this.chart['labels'] = this.getLabels(lodash.sortBy(this.samplesList[project_id], 'timestamp'));
323 this.chart['series'].push(project_id);
324 this.chart['data'].push(this.getData(lodash.sortBy(this.samplesList[project_id], 'timestamp')));
325 this.chartMeters.push(this.samplesList[project_id][0]); //use the 0 as are all samples for the same resource and I need the name
326 lodash.remove(this.sampleLabels, {id: project_id});
Matteo Scandolo68856082015-12-08 14:35:55 -0800327 }
328
Matteo Scandoloe5d5ebd2015-12-14 14:42:28 -0800329 this.removeFromChart = (meter) => {
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800330 this.chart.data.splice(this.chart.series.indexOf(meter.project_id), 1);
331 this.chart.series.splice(this.chart.series.indexOf(meter.project_id), 1);
332 this.chartMeters.splice(lodash.findIndex(this.chartMeters, {project_id: meter.project_id}), 1);
Matteo Scandolo324df092015-12-08 16:39:57 -0800333 this.sampleLabels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800334 id: meter.project_id,
335 name: meter.resource_name || meter.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800336 })
337 };
338
339 /**
340 * Format samples to create a list of labels and ids
341 */
342
343 this.formatSamplesLabels = (samples) => {
344
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800345 return lodash.uniq(samples, 'project_id')
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800346 .reduce((labels, item) => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800347 labels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800348 id: item.project_id,
349 name: item.resource_name || item.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800350 });
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800351
Matteo Scandolo324df092015-12-08 16:39:57 -0800352 return labels;
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800353 }, []);
Matteo Scandolo324df092015-12-08 16:39:57 -0800354 }
355
356
Matteo Scandolo68856082015-12-08 14:35:55 -0800357 /**
358 * Load the samples and format data
359 */
360
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800361 this.showSamples = () => {
362 this.loader = true;
Matteo Scandolo68856082015-12-08 14:35:55 -0800363 // Ceilometer.getSamples(this.name, this.tenant) //fetch one
364 Ceilometer.getSamples(this.name) //fetch all
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800365 .then(res => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800366
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800367 // rename things in UI
368 res.map(m => {
369 m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
370 m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
371 return m;
372 });
373 // end rename things in UI
374
Matteo Scandolo324df092015-12-08 16:39:57 -0800375 // setup data for visualization
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800376 this.samplesList = lodash.groupBy(res, 'project_id');
Matteo Scandolo324df092015-12-08 16:39:57 -0800377 this.sampleLabels = this.formatSamplesLabels(res);
378
379 // add current meter to chart
380 this.addMeterToChart(this.tenant);
381
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800382 })
383 .catch(err => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800384 this.error = err.data.detail;
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800385 })
386 .finally(() => {
387 this.loader = false;
388 });
389 };
390
391 this.showSamples();
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800392 }
393 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800394})
Matteo Scandolobb06c532016-01-28 14:50:16 -0800395 // NOTE reading this on demand for a single
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800396.directive('ceilometerStats', function(){
397 return {
398 restrict: 'E',
399 scope: {
400 name: '=name',
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800401 tenant: '=tenant'
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800402 },
403 bindToController: true,
404 controllerAs: 'vm',
405 templateUrl: 'templates/ceilometer-stats.tpl.html',
406 controller: function($scope, Ceilometer) {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800407
408 this.getStats = (tenant) => {
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800409 this.loader = true;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800410 Ceilometer.getStats({tenant: tenant})
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800411 .then(res => {
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800412 res.map(m => {
413 m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
414 m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
415 return m;
416 });
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800417 this.stats = res;
418 })
419 .catch(err => {
420 this.error = err.data;
421 })
422 .finally(() => {
423 this.loader = false;
424 });
425 };
426
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800427 $scope.$watch(() => this.name, (val) => {
428 if(val){
429 this.getStats(this.tenant);
430 }
431 });
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800432 }
433 }
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800434});