blob: 40233969ef389fcb6fa34889fd71e7db17dc77df [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';
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800144 }
145 if(service.service === 'service_ONOS_vOLT'){
146 service.service = 'ONOS_CORD';
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800147 }
148
Matteo Scandolob03705f82016-03-07 17:54:29 -0800149 service.slices.map(s => {
150 if(s.slice === 'mysite_onos_volt'){
151 s.slice = 'ONOS_CORD';
152 }
153 if(s.slice === 'mysite_onos_vbng'){
154 s.slice = 'ONOS_FABRIC';
155 }
156 if(s.slice === 'mysite_vbng'){
157 s.slice = 'mysite_vRouter';
158 }
159 });
160
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800161 return service;
162 });
163 // end rename thing in UI
164
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800165 this.services = services;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800166 this.openPanels();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800167 })
168 .catch(err => {
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800169 this.error = (err.data && err.data.detail) ? err.data.detail : 'An Error occurred. Please try again later.';
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800170 })
171 .finally(() => {
172 this.loader = false;
173 });
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800174 };
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800175
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800176 this.loadMappings();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800177
Matteo Scandolo68856082015-12-08 14:35:55 -0800178 /**
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800179 * Load the list of a single slice
Matteo Scandolo68856082015-12-08 14:35:55 -0800180 */
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800181
182 this.loadSliceMeter = (slice, service_name) => {
Matteo Scandolo68856082015-12-08 14:35:55 -0800183
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800184 Ceilometer.selectedSlice = null;
185 Ceilometer.selectedService = null;
186 Ceilometer.selectedResources = null;
Matteo Scandolo68856082015-12-08 14:35:55 -0800187
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800188 // visualization info
189 this.loader = true;
Matteo Scandoloba4c9aa2016-02-11 09:35:29 -0800190 this.error = null;
191 this.ceilometerError = null;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800192
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800193 Ceilometer.getMeters({tenant: slice.project_id})
194 .then((sliceMeters) => {
Matteo Scandoloba4c9aa2016-02-11 09:35:29 -0800195 this.selectedSlice = slice.slice;
196 this.selectedTenant = slice.project_id;
197
198 // store the status
199 Ceilometer.selectedSlice = slice;
200 Ceilometer.selectedService = service_name;
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800201
202 // rename things in UI
203 sliceMeters.map(m => {
204 m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
205 m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
Matteo Scandolob03705f82016-03-07 17:54:29 -0800206 m.resource_name = m.resource_name.replace('mysite_vbng', 'mysite_vRouter');
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800207 return m;
208 });
209 // end rename things in UI
210
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800211 this.selectedResources = lodash.groupBy(sliceMeters, 'resource_name');
212
213 // hacky
214 if(Ceilometer.selectedResource){
215 this.selectedMeters = this.selectedResources[Ceilometer.selectedResource];
216 }
217 })
218 .catch(err => {
Matteo Scandoloba4c9aa2016-02-11 09:35:29 -0800219
220 // this means that ceilometer is not yet ready
221 if(err.status === 503){
222 return this.ceilometerError = err.data.detail.specific_error;
223 }
224
Matteo Scandolo81cfbf72016-02-11 09:49:34 -0800225 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 -0800226 })
227 .finally(() => {
228 this.loader = false;
229 });
230 };
Matteo Scandolo68856082015-12-08 14:35:55 -0800231
232 /**
233 * Select Meters for a resource
234 *
235 * @param Array meters The list of selected resources
236 * @returns void
237 */
238 this.selectedMeters = null;
239 this.selectMeters = (meters, resource) => {
240 this.selectedMeters = meters;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800241
242 Ceilometer.selectedResource = resource;
Matteo Scandolo68856082015-12-08 14:35:55 -0800243 this.selectedResource = resource;
244 }
245
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800246 }
247 };
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800248})
249.directive('ceilometerSamples', function(lodash, $stateParams){
250 return {
251 restrict: 'E',
Matteo Scandolo895b30a2016-02-02 16:04:31 -0800252 scope: {},
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800253 bindToController: true,
254 controllerAs: 'vm',
255 templateUrl: 'templates/ceilometer-samples.tpl.html',
256 controller: function(Ceilometer) {
257
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800258 // console.log(Ceilometer.selectResource);
259
Matteo Scandolo324df092015-12-08 16:39:57 -0800260 this.chartColors = [
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800261 '#286090',
262 '#F7464A',
263 '#46BFBD',
264 '#FDB45C',
265 '#97BBCD',
266 '#4D5360',
267 '#8c4f9f'
268 ];
Matteo Scandolo324df092015-12-08 16:39:57 -0800269
270 this.chart = {
271 series: [],
272 labels: [],
273 data: []
274 }
275
276 Chart.defaults.global.colours = this.chartColors;
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800277
Matteo Scandolo68856082015-12-08 14:35:55 -0800278 this.chartType = 'line';
279
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800280 if($stateParams.name && $stateParams.tenant){
281 this.name = $stateParams.name;
282 this.tenant = $stateParams.tenant;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800283 // TODO rename tenant in project_id
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800284 }
Matteo Scandolo1b9ffac2015-12-14 17:36:09 -0800285 else{
286 throw new Error('Missing Name and Tenant Params!');
287 }
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800288
Matteo Scandolo68856082015-12-08 14:35:55 -0800289 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800290 * Goes trough the array and format date to be used as labels
Matteo Scandolo68856082015-12-08 14:35:55 -0800291 *
292 * @param Array data
293 * @returns Array a list of labels
294 */
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800295
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800296 this.getLabels = (data) => {
297 return data.reduce((list, item) => {
298 let date = new Date(item.timestamp);
299 list.push(`${date.getHours()}:${(date.getMinutes()<10?'0':'') + date.getMinutes()}:${date.getSeconds()}`);
300 return list;
301 }, []);
302 };
303
Matteo Scandolo68856082015-12-08 14:35:55 -0800304 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800305 * Goes trough the array and return a flat array of values
Matteo Scandolo68856082015-12-08 14:35:55 -0800306 *
307 * @param Array data
308 * @returns Array a list of values
309 */
310
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800311 this.getData = (data) => {
312 return data.reduce((list, item) => {
313 list.push(item.volume);
314 return list;
315 }, []);
316 }
317
Matteo Scandolo324df092015-12-08 16:39:57 -0800318 /**
319 * Add a samples to the chart
320 *
321 * @param string resource_id
322 */
323 this.chartMeters = [];
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800324 this.addMeterToChart = (project_id) => {
325 this.chart['labels'] = this.getLabels(lodash.sortBy(this.samplesList[project_id], 'timestamp'));
326 this.chart['series'].push(project_id);
327 this.chart['data'].push(this.getData(lodash.sortBy(this.samplesList[project_id], 'timestamp')));
328 this.chartMeters.push(this.samplesList[project_id][0]); //use the 0 as are all samples for the same resource and I need the name
329 lodash.remove(this.sampleLabels, {id: project_id});
Matteo Scandolo68856082015-12-08 14:35:55 -0800330 }
331
Matteo Scandoloe5d5ebd2015-12-14 14:42:28 -0800332 this.removeFromChart = (meter) => {
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800333 this.chart.data.splice(this.chart.series.indexOf(meter.project_id), 1);
334 this.chart.series.splice(this.chart.series.indexOf(meter.project_id), 1);
335 this.chartMeters.splice(lodash.findIndex(this.chartMeters, {project_id: meter.project_id}), 1);
Matteo Scandolo324df092015-12-08 16:39:57 -0800336 this.sampleLabels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800337 id: meter.project_id,
338 name: meter.resource_name || meter.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800339 })
340 };
341
342 /**
343 * Format samples to create a list of labels and ids
344 */
345
346 this.formatSamplesLabels = (samples) => {
347
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800348 return lodash.uniq(samples, 'project_id')
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800349 .reduce((labels, item) => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800350 labels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800351 id: item.project_id,
352 name: item.resource_name || item.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800353 });
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800354
Matteo Scandolo324df092015-12-08 16:39:57 -0800355 return labels;
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800356 }, []);
Matteo Scandolo324df092015-12-08 16:39:57 -0800357 }
358
359
Matteo Scandolo68856082015-12-08 14:35:55 -0800360 /**
361 * Load the samples and format data
362 */
363
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800364 this.showSamples = () => {
365 this.loader = true;
Matteo Scandolo68856082015-12-08 14:35:55 -0800366 // Ceilometer.getSamples(this.name, this.tenant) //fetch one
367 Ceilometer.getSamples(this.name) //fetch all
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800368 .then(res => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800369
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800370 // rename things in UI
371 res.map(m => {
372 m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
373 m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
Matteo Scandolob03705f82016-03-07 17:54:29 -0800374 m.resource_name = m.resource_name.replace('mysite_vbng', 'mysite_vRouter');
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800375 return m;
376 });
377 // end rename things in UI
378
Matteo Scandolo324df092015-12-08 16:39:57 -0800379 // setup data for visualization
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800380 this.samplesList = lodash.groupBy(res, 'project_id');
Matteo Scandolo324df092015-12-08 16:39:57 -0800381 this.sampleLabels = this.formatSamplesLabels(res);
382
383 // add current meter to chart
384 this.addMeterToChart(this.tenant);
385
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800386 })
387 .catch(err => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800388 this.error = err.data.detail;
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800389 })
390 .finally(() => {
391 this.loader = false;
392 });
393 };
394
395 this.showSamples();
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800396 }
397 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800398})
Matteo Scandolobb06c532016-01-28 14:50:16 -0800399 // NOTE reading this on demand for a single
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800400.directive('ceilometerStats', function(){
401 return {
402 restrict: 'E',
403 scope: {
404 name: '=name',
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800405 tenant: '=tenant'
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800406 },
407 bindToController: true,
408 controllerAs: 'vm',
409 templateUrl: 'templates/ceilometer-stats.tpl.html',
410 controller: function($scope, Ceilometer) {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800411
412 this.getStats = (tenant) => {
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800413 this.loader = true;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800414 Ceilometer.getStats({tenant: tenant})
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800415 .then(res => {
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800416 res.map(m => {
417 m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
418 m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
Matteo Scandolob03705f82016-03-07 17:54:29 -0800419 m.resource_name = m.resource_name.replace('mysite_vbng', 'mysite_vRouter');
Matteo Scandolo999d3a12016-03-07 17:50:38 -0800420 return m;
421 });
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800422 this.stats = res;
423 })
424 .catch(err => {
425 this.error = err.data;
426 })
427 .finally(() => {
428 this.loader = false;
429 });
430 };
431
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800432 $scope.$watch(() => this.name, (val) => {
433 if(val){
434 this.getStats(this.tenant);
435 }
436 });
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800437 }
438 }
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800439});