blob: aeb8243f9e0ce7b78e051a838f32013178632080 [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 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: {}
113 }
114
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) => {
139 this.services = services;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800140 this.openPanels();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800141 })
142 .catch(err => {
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800143 this.error = (err.data && err.data.detail) ? err.data.detail : 'An Error occurred. Please try again later.';
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800144 })
145 .finally(() => {
146 this.loader = false;
147 });
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800148 };
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800149
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800150 this.loadMappings();
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800151
Matteo Scandolo68856082015-12-08 14:35:55 -0800152 /**
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800153 * Load the list of a single slice
Matteo Scandolo68856082015-12-08 14:35:55 -0800154 */
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800155
156 this.loadSliceMeter = (slice, service_name) => {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800157
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800158 Ceilometer.selectedSlice = null;
159 Ceilometer.selectedService = null;
160 Ceilometer.selectedResources = null;
Matteo Scandolo68856082015-12-08 14:35:55 -0800161
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800162 // visualization info
163 this.loader = true;
164 this.selectedSlice = slice.slice;
165 this.selectedTenant = slice.project_id;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800166
167 // store the status
168 Ceilometer.selectedSlice = slice;
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800169 Ceilometer.selectedService = service_name;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800170
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800171 Ceilometer.getMeters({tenant: slice.project_id})
172 .then((sliceMeters) => {
173 this.selectedResources = lodash.groupBy(sliceMeters, 'resource_name');
174
175 // hacky
176 if(Ceilometer.selectedResource){
177 this.selectedMeters = this.selectedResources[Ceilometer.selectedResource];
178 }
179 })
180 .catch(err => {
181 this.error = (err.data && err.data.detail) ? err.data.detail : 'An Error occurred. Please try again later.';
182 })
183 .finally(() => {
184 this.loader = false;
185 });
186 };
Matteo Scandolo68856082015-12-08 14:35:55 -0800187
188 /**
189 * Select Meters for a resource
190 *
191 * @param Array meters The list of selected resources
192 * @returns void
193 */
194 this.selectedMeters = null;
195 this.selectMeters = (meters, resource) => {
196 this.selectedMeters = meters;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800197
198 Ceilometer.selectedResource = resource;
Matteo Scandolo68856082015-12-08 14:35:55 -0800199 this.selectedResource = resource;
200 }
201
Matteo Scandolo68c2e722015-12-04 10:14:40 -0800202 }
203 };
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800204})
205.directive('ceilometerSamples', function(lodash, $stateParams){
206 return {
207 restrict: 'E',
Matteo Scandolo895b30a2016-02-02 16:04:31 -0800208 scope: {},
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800209 bindToController: true,
210 controllerAs: 'vm',
211 templateUrl: 'templates/ceilometer-samples.tpl.html',
212 controller: function(Ceilometer) {
213
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800214 // console.log(Ceilometer.selectResource);
215
Matteo Scandolo324df092015-12-08 16:39:57 -0800216 this.chartColors = [
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800217 '#286090',
218 '#F7464A',
219 '#46BFBD',
220 '#FDB45C',
221 '#97BBCD',
222 '#4D5360',
223 '#8c4f9f'
224 ];
Matteo Scandolo324df092015-12-08 16:39:57 -0800225
226 this.chart = {
227 series: [],
228 labels: [],
229 data: []
230 }
231
232 Chart.defaults.global.colours = this.chartColors;
Matteo Scandolo2b6583e2015-12-08 15:24:23 -0800233
Matteo Scandolo68856082015-12-08 14:35:55 -0800234 this.chartType = 'line';
235
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800236 if($stateParams.name && $stateParams.tenant){
237 this.name = $stateParams.name;
238 this.tenant = $stateParams.tenant;
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800239 // TODO rename tenant in project_id
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800240 }
Matteo Scandolo1b9ffac2015-12-14 17:36:09 -0800241 else{
242 throw new Error('Missing Name and Tenant Params!');
243 }
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800244
Matteo Scandolo68856082015-12-08 14:35:55 -0800245 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800246 * Goes trough the array and format date to be used as labels
Matteo Scandolo68856082015-12-08 14:35:55 -0800247 *
248 * @param Array data
249 * @returns Array a list of labels
250 */
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800251
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800252 this.getLabels = (data) => {
253 return data.reduce((list, item) => {
254 let date = new Date(item.timestamp);
255 list.push(`${date.getHours()}:${(date.getMinutes()<10?'0':'') + date.getMinutes()}:${date.getSeconds()}`);
256 return list;
257 }, []);
258 };
259
Matteo Scandolo68856082015-12-08 14:35:55 -0800260 /**
Matteo Scandolo324df092015-12-08 16:39:57 -0800261 * Goes trough the array and return a flat array of values
Matteo Scandolo68856082015-12-08 14:35:55 -0800262 *
263 * @param Array data
264 * @returns Array a list of values
265 */
266
Matteo Scandolo1d8627f2015-12-05 18:44:45 -0800267 this.getData = (data) => {
268 return data.reduce((list, item) => {
269 list.push(item.volume);
270 return list;
271 }, []);
272 }
273
Matteo Scandolo324df092015-12-08 16:39:57 -0800274 /**
275 * Add a samples to the chart
276 *
277 * @param string resource_id
278 */
279 this.chartMeters = [];
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800280 this.addMeterToChart = (project_id) => {
281 this.chart['labels'] = this.getLabels(lodash.sortBy(this.samplesList[project_id], 'timestamp'));
282 this.chart['series'].push(project_id);
283 this.chart['data'].push(this.getData(lodash.sortBy(this.samplesList[project_id], 'timestamp')));
284 this.chartMeters.push(this.samplesList[project_id][0]); //use the 0 as are all samples for the same resource and I need the name
285 lodash.remove(this.sampleLabels, {id: project_id});
Matteo Scandolo68856082015-12-08 14:35:55 -0800286 }
287
Matteo Scandoloe5d5ebd2015-12-14 14:42:28 -0800288 this.removeFromChart = (meter) => {
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800289 this.chart.data.splice(this.chart.series.indexOf(meter.project_id), 1);
290 this.chart.series.splice(this.chart.series.indexOf(meter.project_id), 1);
291 this.chartMeters.splice(lodash.findIndex(this.chartMeters, {project_id: meter.project_id}), 1);
Matteo Scandolo324df092015-12-08 16:39:57 -0800292 this.sampleLabels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800293 id: meter.project_id,
294 name: meter.resource_name || meter.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800295 })
296 };
297
298 /**
299 * Format samples to create a list of labels and ids
300 */
301
302 this.formatSamplesLabels = (samples) => {
303
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800304 return lodash.uniq(samples, 'project_id')
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800305 .reduce((labels, item) => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800306 labels.push({
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800307 id: item.project_id,
308 name: item.resource_name || item.project_id
Matteo Scandolo324df092015-12-08 16:39:57 -0800309 });
310 return labels;
Matteo Scandolo5074ccd2015-12-15 08:16:56 -0800311 }, []);
Matteo Scandolo324df092015-12-08 16:39:57 -0800312 }
313
314
Matteo Scandolo68856082015-12-08 14:35:55 -0800315 /**
316 * Load the samples and format data
317 */
318
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800319 this.showSamples = () => {
320 this.loader = true;
Matteo Scandolo68856082015-12-08 14:35:55 -0800321 // Ceilometer.getSamples(this.name, this.tenant) //fetch one
322 Ceilometer.getSamples(this.name) //fetch all
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800323 .then(res => {
Matteo Scandolo324df092015-12-08 16:39:57 -0800324
325 // setup data for visualization
Matteo Scandolo6c6b9282015-12-15 14:37:27 -0800326 this.samplesList = lodash.groupBy(res, 'project_id');
Matteo Scandolo324df092015-12-08 16:39:57 -0800327 this.sampleLabels = this.formatSamplesLabels(res);
328
329 // add current meter to chart
330 this.addMeterToChart(this.tenant);
331
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800332 })
333 .catch(err => {
Matteo Scandoloc8f18e62015-12-09 15:23:51 -0800334 this.error = err.data.detail;
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800335 })
336 .finally(() => {
337 this.loader = false;
338 });
339 };
340
341 this.showSamples();
Matteo Scandolo7b80d842015-12-04 15:55:20 -0800342 }
343 }
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800344})
345.directive('ceilometerStats', function(){
346 return {
347 restrict: 'E',
348 scope: {
349 name: '=name',
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800350 tenant: '=tenant'
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800351 },
352 bindToController: true,
353 controllerAs: 'vm',
354 templateUrl: 'templates/ceilometer-stats.tpl.html',
355 controller: function($scope, Ceilometer) {
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800356
357 this.getStats = (tenant) => {
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800358 this.loader = true;
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800359 Ceilometer.getStats({tenant: tenant})
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800360 .then(res => {
361 this.stats = res;
362 })
363 .catch(err => {
364 this.error = err.data;
365 })
366 .finally(() => {
367 this.loader = false;
368 });
369 };
370
Matteo Scandolo19c2a4e2016-02-02 16:29:40 -0800371 $scope.$watch(() => this.name, (val) => {
372 if(val){
373 this.getStats(this.tenant);
374 }
375 });
Matteo Scandolo41f5c152015-12-09 17:09:55 -0800376 }
377 }
Matteo Scandolo9db064f2016-02-08 14:17:42 -0800378});