blob: 50a276cefc98908637fab6eb949113f6968d7c22 [file] [log] [blame]
Matteo Scandolo8a64fa42016-01-21 11:21:03 -08001(function () {
2 'use strict';
3
Matteo Scandolo04564952016-02-24 11:22:48 -08004 angular.module('xos.diagnostic')
Matteo Scandolo8a64fa42016-01-21 11:21:03 -08005 .service('Services', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -07006 return $resource('/api/core/services/:id', {id: '@id'});
Matteo Scandolof16b3792016-01-21 14:23:28 -08007 })
8 .service('Tenant', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -07009 return $resource('/api/core/tenants', {id: '@id'}, {
Matteo Scandolo51031482016-02-17 13:54:11 -080010 queryVsgInstances: {
11 method: 'GET',
12 isArray: true,
13 interceptor: {
14 response: (res) => {
15
16 // NOTE
17 // Note that VCPETenant is now VSGTenant.
18
19 let instances = [];
20
21 angular.forEach(res.data, (tenant) => {
22 let info = JSON.parse(tenant.service_specific_attribute);
23 if(info && info.instance_id){
24 instances.push(info.instance_id);
25 }
26 });
27
28 return instances;
29 }
30 }
Matteo Scandolo45fba732016-02-22 14:53:44 -080031 },
32 getSubscriberTag: {
33 method: 'GET',
34 isArray: true,
35 interceptor: {
36 response: (res) => {
37 // NOTE we should receive only one vOLT tenant here
38 return JSON.parse(res.data[0].service_specific_attribute);
39 }
40 }
Matteo Scandolo51031482016-02-17 13:54:11 -080041 }
42 });
43 })
44 .service('Ceilometer', function($http, $q, Instances) {
45
46 /**
47 * Get stats for a single instance
48 */
49 this.getInstanceStats = (instanceUuid) => {
50 let deferred = $q.defer();
51
Matteo Scandolof0d6e692016-02-24 11:14:01 -080052 $http.get('/xoslib/xos-instance-statistics', {params: {'instance-uuid': instanceUuid}})
Matteo Scandolo51031482016-02-17 13:54:11 -080053 .then((res) => {
54 deferred.resolve(res.data);
55 })
56 .catch((e) => {
57 deferred.reject(e);
58 })
59
60 return deferred.promise;
61 };
62
63 /**
64 * Collect stats for an array of instances
65 */
66 this.getInstancesStats = (instances) => {
67 let deferred = $q.defer();
68 let instancePromises = [];
69 let instanceList = [];
70
71 // retrieve instance details
72 instances.forEach((instanceId) => {
73 instancePromises.push(Instances.get({id: instanceId}).$promise);
74 });
75
76 // get all instance data
77 $q.all(instancePromises)
78 .then((_instanceList) => {
79 instanceList = _instanceList;
80 let promises = [];
81 // foreach instance query stats
82 instanceList.forEach((instance) => {
83 promises.push(this.getInstanceStats(instance.instance_uuid));
84 });
85 return $q.all(promises);
86 })
87 .then(stats => {
88 // augment instance with stats information
89 instanceList.map((instance, i) => {
90 instance.stats = stats[i];
91 });
92 deferred.resolve(instanceList);
93 })
94 .catch(deferred.reject);
95
96 return deferred.promise;
97 };
Matteo Scandolof0d6e692016-02-24 11:14:01 -080098
99 this.getContainerStats = (containerName) => {
100 const deferred = $q.defer();
101
102 let res = {};
103
104 $http.get('/xoslib/meterstatistics', {params: {'resource': containerName}})
105 .then((containerStats) => {
106 res.stats = containerStats.data;
107 return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth0`}})
108 })
109 .then((portStats) => {
110 res.port = {
111 eth0: portStats.data
112 };
113 return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth1`}})
114 })
115 .then((portStats) => {
116 res.port.eth1 = portStats.data;
117 deferred.resolve(res);
118 })
119 .catch((e) => {
120 deferred.reject(e);
121 })
122
123 return deferred.promise;
124 }
Matteo Scandolof16b3792016-01-21 14:23:28 -0800125 })
Matteo Scandolo06f45d62016-01-21 15:38:06 -0800126 .service('Slice', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -0700127 return $resource('/api/core/slices', {id: '@id'});
Matteo Scandolo06f45d62016-01-21 15:38:06 -0800128 })
129 .service('Instances', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -0700130 return $resource('/api/core/instances/:id', {id: '@id'});
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800131 })
132 .service('Node', function($resource, $q, Instances){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -0700133 return $resource('/api/core/nodes', {id: '@id'}, {
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800134 queryWithInstances: {
135 method: 'GET',
136 isArray: true,
137 interceptor: {
138 response: function(res){
139
140 // TODO update the API to include instances in nodes
141 // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
142
143 const deferred = $q.defer();
144
145 let requests = [];
146
147 angular.forEach(res.data, (node) => {
148 requests.push(Instances.query({node: node.id}).$promise);
149 })
150
151 $q.all(requests)
152 .then((list) => {
153 res.data.map((node, i) => {
154 node.instances = list[i];
155 return node;
156 });
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800157 deferred.resolve(res.data);
158 })
159
160 return deferred.promise;
161 }
162 }
163 }
164 });
Matteo Scandolo06f45d62016-01-21 15:38:06 -0800165 })
Matteo Scandoloe64dcc02016-08-02 11:53:22 -0700166 // TODO extend the resource in xosLib
167 .service('SubscribersWithDevice', function($http, $q, Subscribers){
Matteo Scandolo219b1a72016-02-09 11:19:22 -0800168
Matteo Scandoloe64dcc02016-08-02 11:53:22 -0700169 this.get = (s) => {
170 const d = $q.defer();
171 let subscriber;
Matteo Scandolo219b1a72016-02-09 11:19:22 -0800172
Matteo Scandoloe64dcc02016-08-02 11:53:22 -0700173 Subscribers.get({id: s.id}).$promise
174 .then(res => {
175 subscriber = res;
176 return $http.get(`/api/tenant/cord/subscriber/${subscriber.id}/devices/`);
177 })
178 .then(res => {
179 res.data.map(d => d.type = 'device');
180 subscriber.devices = res.data;
181 subscriber.type = 'subscriber';
182 d.resolve(subscriber);
183 })
184 .catch(err => {
185 d.reject(err);
186 });
187 return {$promise: d.promise};
188 };
Matteo Scandolo7547f042016-02-09 09:13:30 -0800189
Matteo Scandoloff7df762016-01-22 16:36:34 -0800190 })
Matteo Scandolofe307b12016-05-17 14:29:01 -0700191 .service('ServiceRelation', function($q, _, Services, Tenant, Slice, Instances){
Matteo Scandolof16b3792016-01-21 14:23:28 -0800192
Matteo Scandolof2c99012016-01-25 10:10:38 -0800193 // count the mas depth of an object
194 const depthOf = (obj) => {
195 var depth = 0;
196 if (obj.children) {
197 obj.children.forEach(function (d) {
198 var tmpDepth = depthOf(d);
199 if (tmpDepth > depth) {
200 depth = tmpDepth
201 }
202 })
203 }
204 return 1 + depth
205 };
206
Matteo Scandolof16b3792016-01-21 14:23:28 -0800207 // find all the relation defined for a given root
208 const findLevelRelation = (tenants, rootId) => {
Matteo Scandolofe307b12016-05-17 14:29:01 -0700209 return _.filter(tenants, service => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800210 return service.subscriber_service === rootId;
211 });
212 };
213
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800214 const findSpecificInformation = (tenants, rootId) => {
Matteo Scandolofe307b12016-05-17 14:29:01 -0700215 var tenants = _.filter(tenants, service => {
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800216 return service.provider_service === rootId && service.subscriber_tenant;
217 });
218
219 var info;
220
221 tenants.forEach((tenant) => {
222 if(tenant.service_specific_attribute){
223 info = JSON.parse(tenant.service_specific_attribute);
224 }
225 });
226
227 return info;
228 };
229
Matteo Scandolof16b3792016-01-21 14:23:28 -0800230 // find all the service defined by a given array of relations
231 const findLevelServices = (relations, services) => {
232 const levelServices = [];
Matteo Scandolofe307b12016-05-17 14:29:01 -0700233 _.forEach(relations, (tenant) => {
234 var service = _.find(services, {id: tenant.provider_service});
Matteo Scandolof16b3792016-01-21 14:23:28 -0800235 levelServices.push(service);
236 });
237 return levelServices;
238 };
239
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800240 const buildLevel = (tenants, services, rootService, rootTenant, parentName = null) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800241
Matteo Scandolof16b3792016-01-21 14:23:28 -0800242 // build an array of unlinked services
243 // these are the services that should still placed in the tree
Matteo Scandolofe307b12016-05-17 14:29:01 -0700244 var unlinkedServices = _.difference(services, [rootService]);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800245
246 // find all relations relative to this rootElement
247 const levelRelation = findLevelRelation(tenants, rootService.id);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800248 // find all items related to rootElement
249 const levelServices = findLevelServices(levelRelation, services);
250
251 // remove this item from the list (performance
Matteo Scandolofe307b12016-05-17 14:29:01 -0700252 unlinkedServices = _.difference(unlinkedServices, levelServices);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800253
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800254 rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
255
Matteo Scandolo384ff562016-03-07 17:58:34 -0800256 if(rootService.humanReadableName === 'service_vbng'){
257 rootService.humanReadableName = 'service_vrouter'
258 }
259
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800260 const tree = {
261 name: rootService.humanReadableName,
262 parent: parentName,
263 type: 'service',
264 service: rootService,
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800265 tenant: rootTenant,
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800266 children: []
267 };
268
Matteo Scandolofe307b12016-05-17 14:29:01 -0700269 _.forEach(levelServices, (service) => {
Matteo Scandolo930e4fd2016-03-07 16:41:25 -0800270 if(service.humanReadableName === 'service_ONOS_vBNG' || service.humanReadableName === 'service_ONOS_vOLT'){
271 // remove ONOSes from service chart
272 return;
273 }
Matteo Scandolofe307b12016-05-17 14:29:01 -0700274 let tenant = _.find(tenants, {subscriber_tenant: rootTenant.id, provider_service: service.id});
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800275 tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
Matteo Scandolof16b3792016-01-21 14:23:28 -0800276 });
277
Matteo Scandolof2c99012016-01-25 10:10:38 -0800278 // if it is the last element append internet
279 if(tree.children.length === 0){
280 tree.children.push({
Matteo Scandolo9fe01af2016-02-09 16:01:49 -0800281 name: 'Router',
282 type: 'router',
Matteo Scandolof2c99012016-01-25 10:10:38 -0800283 children: []
284 });
285 }
286
Matteo Scandolof16b3792016-01-21 14:23:28 -0800287 return tree;
288 };
289
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800290 const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800291
292 // find the root service
293 // it is the one attached to subsriber_root
294 // as now we have only one root so this can work
Matteo Scandolofe307b12016-05-17 14:29:01 -0700295 const rootTenant = _.find(tenants, {subscriber_root: subscriber.id});
296 const rootService = _.find(services, {id: rootTenant.provider_service});
Matteo Scandolof16b3792016-01-21 14:23:28 -0800297
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800298 const serviceTree = buildLevel(tenants, services, rootService, rootTenant);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800299
Matteo Scandoloff7df762016-01-22 16:36:34 -0800300 return {
Matteo Scandolod4ea8772016-03-01 15:20:29 -0800301 name: subscriber.name || subscriber.humanReadableName,
Matteo Scandoloff7df762016-01-22 16:36:34 -0800302 parent: null,
Matteo Scandolof2c99012016-01-25 10:10:38 -0800303 type: 'subscriber',
Matteo Scandoloff7df762016-01-22 16:36:34 -0800304 children: [serviceTree]
305 };
306
Matteo Scandolof16b3792016-01-21 14:23:28 -0800307 };
308
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800309 // applying domain knowledge to build the global service tree
310 const buildServiceTree = (services, tenants) => {
311
312 // TODO refactor
313 const buildChild = (services, tenants, currentService) => {
Matteo Scandolo45fba732016-02-22 14:53:44 -0800314
Matteo Scandolo384ff562016-03-07 17:58:34 -0800315 if(currentService.humanReadableName === 'service_vbng'){
316 currentService.humanReadableName = 'service_vrouter'
317 }
318
Matteo Scandolo45fba732016-02-22 14:53:44 -0800319 const response = {
320 type: 'service',
321 name: currentService.humanReadableName,
322 service: currentService
323 };
324
Matteo Scandolofe307b12016-05-17 14:29:01 -0700325 let tenant = _.find(tenants, {subscriber_service: currentService.id});
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800326 if(tenant){
Matteo Scandolofe307b12016-05-17 14:29:01 -0700327 let next = _.find(services, {id: tenant.provider_service});
Matteo Scandolo45fba732016-02-22 14:53:44 -0800328 response.children = [buildChild(services, tenants, next)];
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800329 }
330 else {
Matteo Scandolo45fba732016-02-22 14:53:44 -0800331 response.children = [
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800332 {
333 name: 'Router',
334 type: 'router',
335 children: []
336 }
337 ]
338 }
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800339 delete currentService.id; // conflict with d3
Matteo Scandolo45fba732016-02-22 14:53:44 -0800340 return response;
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800341 }
Matteo Scandolo70ac2162016-02-24 15:40:22 -0800342
Matteo Scandolofe307b12016-05-17 14:29:01 -0700343 let baseService = _.find(services, {id: 3});
Matteo Scandolo70ac2162016-02-24 15:40:22 -0800344
345 if(!angular.isDefined(baseService)){
346 console.error('Missing Base service!');
347 return;
348 }
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800349
350 const baseData = {
351 name: 'Subscriber',
352 type: 'subscriber',
353 parent: null,
354 children: [buildChild(services, tenants, baseService)]
355 };
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800356 return baseData;
357 };
358
359 const getBySubscriber = (subscriber) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800360 var deferred = $q.defer();
361 var services, tenants;
362 Services.query().$promise
363 .then((res) => {
364 services = res;
365 return Tenant.query().$promise;
366 })
367 .then((res) => {
368 tenants = res;
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800369 deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
Matteo Scandolof16b3792016-01-21 14:23:28 -0800370 })
371 .catch((e) => {
372 throw new Error(e);
373 });
374
375 return deferred.promise;
Matteo Scandolof2c99012016-01-25 10:10:38 -0800376 };
Matteo Scandoloff7df762016-01-22 16:36:34 -0800377
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800378 const get = () => {
379 var deferred = $q.defer();
380 var services, tenants;
381 Services.query().$promise
382 .then((res) => {
383 services = res;
384 return Tenant.query({kind: 'coarse'}).$promise;
385 })
386 .then((res) => {
387 tenants = res;
388 deferred.resolve(buildServiceTree(services, tenants));
389 })
390 .catch((e) => {
391 throw new Error(e);
392 });
393
394 return deferred.promise;
395 }
396
Matteo Scandolof2c99012016-01-25 10:10:38 -0800397 // export APIs
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800398 return {
399 get: get,
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800400 buildServiceTree: buildServiceTree,
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800401 getBySubscriber: getBySubscriber,
402 buildLevel: buildLevel,
403 buildSubscriberServiceTree: buildSubscriberServiceTree,
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800404 findLevelRelation: findLevelRelation,
405 findLevelServices: findLevelServices,
406 depthOf: depthOf,
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800407 findSpecificInformation: findSpecificInformation
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800408 }
Matteo Scandolo8a64fa42016-01-21 11:21:03 -0800409 });
410
411}());