blob: 5677f307e908f4d6f5bf67d65712e4fc5543f993 [file] [log] [blame]
Matteo Scandolobe9b13d2016-01-21 11:21:03 -08001(function () {
2 'use strict';
3
Matteo Scandolo4b3d8722016-02-24 11:22:48 -08004 angular.module('xos.diagnostic')
Matteo Scandolobe9b13d2016-01-21 11:21:03 -08005 .service('Services', function($resource){
Matteo Scandolo85aad312016-01-21 14:23:28 -08006 return $resource('/xos/services/:id', {id: '@id'});
7 })
8 .service('Tenant', function($resource){
Matteo Scandoloba2d63d2016-02-17 13:54:11 -08009 return $resource('/xos/tenants', {id: '@id'}, {
10 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 Scandolodffc1382016-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 Scandoloba2d63d2016-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 Scandolo653c5092016-02-24 11:14:01 -080052 $http.get('/xoslib/xos-instance-statistics', {params: {'instance-uuid': instanceUuid}})
Matteo Scandoloba2d63d2016-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 Scandolo653c5092016-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 Scandolo85aad312016-01-21 14:23:28 -0800125 })
Matteo Scandolo68236262016-01-21 15:38:06 -0800126 .service('Slice', function($resource){
127 return $resource('/xos/slices', {id: '@id'});
128 })
129 .service('Instances', function($resource){
Matteo Scandoloba2d63d2016-02-17 13:54:11 -0800130 return $resource('/xos/instances/:id', {id: '@id'});
Matteo Scandolo14183932016-02-11 08:58:04 -0800131 })
132 .service('Node', function($resource, $q, Instances){
133 return $resource('/xos/nodes', {id: '@id'}, {
134 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 Scandolo14183932016-02-11 08:58:04 -0800157 deferred.resolve(res.data);
158 })
159
160 return deferred.promise;
161 }
162 }
163 }
164 });
Matteo Scandolo68236262016-01-21 15:38:06 -0800165 })
Matteo Scandolo735606c2016-02-09 09:13:30 -0800166 .service('Subscribers', function($resource, $q, SubscriberDevice){
Matteo Scandoloa03110c2016-03-01 15:20:29 -0800167 return $resource('/xoslib/cordsubscriber/:id', {id: '@id'}, {
Matteo Scandolo5fc82c32016-03-02 10:59:46 -0800168 update: {
169 method: 'PUT',
170 isArray: false
171 },
Matteo Scandolo735606c2016-02-09 09:13:30 -0800172 queryWithDevices: {
173 method: 'GET',
174 isArray: true,
175 interceptor: {
176 response: function(res){
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800177
178 /**
179 * For each subscriber retrieve devices and append them
180 */
181
Matteo Scandolodffc1382016-02-22 14:53:44 -0800182 let deferred = $q.defer();
Matteo Scandolo735606c2016-02-09 09:13:30 -0800183
184 let requests = [];
185
186 angular.forEach(res.data, (subscriber) => {
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800187 requests.push(SubscriberDevice.query({id: subscriber.id}).$promise);
Matteo Scandolo735606c2016-02-09 09:13:30 -0800188 })
189
190 $q.all(requests)
191 .then((list) => {
Matteo Scandolo4aae3aa2016-02-16 16:33:26 -0800192
193 // adding devices
194
Matteo Scandolo735606c2016-02-09 09:13:30 -0800195 res.data.map((subscriber, i) => {
196 subscriber.devices = list[i];
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800197 subscriber.type = 'subscriber';
198
199 subscriber.devices.map(d => d.type = 'device')
200
Matteo Scandolo735606c2016-02-09 09:13:30 -0800201 return subscriber;
202 });
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800203
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800204 // faking to have 2 subscriber
Matteo Scandoloc2c6fb02016-02-16 16:03:43 -0800205 // res.data.push(angular.copy(res.data[0]));
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800206
Matteo Scandolo735606c2016-02-09 09:13:30 -0800207 deferred.resolve(res.data);
208 })
209
210 return deferred.promise;
211 }
212 }
Matteo Scandolodffc1382016-02-22 14:53:44 -0800213 },
214 getWithDevices: {
215 method: 'GET',
216 isArray: false,
217 interceptor: {
218 response: (res) => {
219 let d = $q.defer();
220
221 SubscriberDevice.query({id: res.data.id}).$promise
222 .then(devices => {
223 devices.map(d => d.type = 'device');
224 res.data.devices = devices;
225 res.data.type = 'subscriber';
Matteo Scandolodffc1382016-02-22 14:53:44 -0800226 d.resolve(res.data);
227 })
228 .catch(err => {
229 d.reject(err);
230 });
231
232 return d.promise;
233 }
234 }
Matteo Scandolo735606c2016-02-09 09:13:30 -0800235 }
236 });
237 })
238 .service('SubscriberDevice', function($resource){
239 return $resource('/xoslib/rs/subscriber/:id/users/', {id: '@id'});
Matteo Scandolo89276392016-01-22 16:36:34 -0800240 })
Matteo Scandolo4889f5a2016-01-25 12:00:42 -0800241 .service('ServiceRelation', function($q, lodash, Services, Tenant, Slice, Instances){
Matteo Scandolo85aad312016-01-21 14:23:28 -0800242
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800243 // count the mas depth of an object
244 const depthOf = (obj) => {
245 var depth = 0;
246 if (obj.children) {
247 obj.children.forEach(function (d) {
248 var tmpDepth = depthOf(d);
249 if (tmpDepth > depth) {
250 depth = tmpDepth
251 }
252 })
253 }
254 return 1 + depth
255 };
256
Matteo Scandolo85aad312016-01-21 14:23:28 -0800257 // find all the relation defined for a given root
258 const findLevelRelation = (tenants, rootId) => {
259 return lodash.filter(tenants, service => {
260 return service.subscriber_service === rootId;
261 });
262 };
263
Matteo Scandolo998e4652016-01-28 12:02:57 -0800264 const findSpecificInformation = (tenants, rootId) => {
265 var tenants = lodash.filter(tenants, service => {
266 return service.provider_service === rootId && service.subscriber_tenant;
267 });
268
269 var info;
270
271 tenants.forEach((tenant) => {
272 if(tenant.service_specific_attribute){
273 info = JSON.parse(tenant.service_specific_attribute);
274 }
275 });
276
277 return info;
278 };
279
Matteo Scandolo85aad312016-01-21 14:23:28 -0800280 // find all the service defined by a given array of relations
281 const findLevelServices = (relations, services) => {
282 const levelServices = [];
283 lodash.forEach(relations, (tenant) => {
284 var service = lodash.find(services, {id: tenant.provider_service});
285 levelServices.push(service);
286 });
287 return levelServices;
288 };
289
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800290 const buildLevel = (tenants, services, rootService, rootTenant, parentName = null) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800291
Matteo Scandolo85aad312016-01-21 14:23:28 -0800292 // build an array of unlinked services
293 // these are the services that should still placed in the tree
294 var unlinkedServices = lodash.difference(services, [rootService]);
295
296 // find all relations relative to this rootElement
297 const levelRelation = findLevelRelation(tenants, rootService.id);
Matteo Scandolo85aad312016-01-21 14:23:28 -0800298 // find all items related to rootElement
299 const levelServices = findLevelServices(levelRelation, services);
300
301 // remove this item from the list (performance
302 unlinkedServices = lodash.difference(unlinkedServices, levelServices);
303
Matteo Scandolo998e4652016-01-28 12:02:57 -0800304 rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
305
306 const tree = {
307 name: rootService.humanReadableName,
308 parent: parentName,
309 type: 'service',
310 service: rootService,
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800311 tenant: rootTenant,
Matteo Scandolo998e4652016-01-28 12:02:57 -0800312 children: []
313 };
314
Matteo Scandolo85aad312016-01-21 14:23:28 -0800315 lodash.forEach(levelServices, (service) => {
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800316 let tenant = lodash.find(tenants, {subscriber_tenant: rootTenant.id, provider_service: service.id});
317 tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
Matteo Scandolo85aad312016-01-21 14:23:28 -0800318 });
319
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800320 // if it is the last element append internet
321 if(tree.children.length === 0){
322 tree.children.push({
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800323 name: 'Router',
324 type: 'router',
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800325 children: []
326 });
327 }
328
Matteo Scandolo85aad312016-01-21 14:23:28 -0800329 return tree;
330 };
331
Matteo Scandolo657d1322016-02-16 17:43:00 -0800332 const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800333
334 // find the root service
335 // it is the one attached to subsriber_root
336 // as now we have only one root so this can work
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800337 const rootTenant = lodash.find(tenants, {subscriber_root: subscriber.id});
338 const rootService = lodash.find(services, {id: rootTenant.provider_service});
Matteo Scandolo85aad312016-01-21 14:23:28 -0800339
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800340 const serviceTree = buildLevel(tenants, services, rootService, rootTenant);
Matteo Scandolo85aad312016-01-21 14:23:28 -0800341
Matteo Scandolo89276392016-01-22 16:36:34 -0800342 return {
Matteo Scandoloa03110c2016-03-01 15:20:29 -0800343 name: subscriber.name || subscriber.humanReadableName,
Matteo Scandolo89276392016-01-22 16:36:34 -0800344 parent: null,
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800345 type: 'subscriber',
Matteo Scandolo89276392016-01-22 16:36:34 -0800346 children: [serviceTree]
347 };
348
Matteo Scandolo85aad312016-01-21 14:23:28 -0800349 };
350
Matteo Scandolo657d1322016-02-16 17:43:00 -0800351 // applying domain knowledge to build the global service tree
352 const buildServiceTree = (services, tenants) => {
353
354 // TODO refactor
355 const buildChild = (services, tenants, currentService) => {
Matteo Scandolodffc1382016-02-22 14:53:44 -0800356
357 const response = {
358 type: 'service',
359 name: currentService.humanReadableName,
360 service: currentService
361 };
362
Matteo Scandolo657d1322016-02-16 17:43:00 -0800363 let tenant = lodash.find(tenants, {subscriber_service: currentService.id});
364 if(tenant){
365 let next = lodash.find(services, {id: tenant.provider_service});
Matteo Scandolodffc1382016-02-22 14:53:44 -0800366 response.children = [buildChild(services, tenants, next)];
Matteo Scandolo657d1322016-02-16 17:43:00 -0800367 }
368 else {
Matteo Scandolodffc1382016-02-22 14:53:44 -0800369 response.children = [
Matteo Scandolo657d1322016-02-16 17:43:00 -0800370 {
371 name: 'Router',
372 type: 'router',
373 children: []
374 }
375 ]
376 }
Matteo Scandolo657d1322016-02-16 17:43:00 -0800377 delete currentService.id; // conflict with d3
Matteo Scandolodffc1382016-02-22 14:53:44 -0800378 return response;
Matteo Scandolo657d1322016-02-16 17:43:00 -0800379 }
Matteo Scandolo16763e92016-02-24 15:40:22 -0800380
Matteo Scandolo657d1322016-02-16 17:43:00 -0800381 let baseService = lodash.find(services, {id: 3});
Matteo Scandolo16763e92016-02-24 15:40:22 -0800382
383 if(!angular.isDefined(baseService)){
384 console.error('Missing Base service!');
385 return;
386 }
Matteo Scandolo657d1322016-02-16 17:43:00 -0800387
388 const baseData = {
389 name: 'Subscriber',
390 type: 'subscriber',
391 parent: null,
392 children: [buildChild(services, tenants, baseService)]
393 };
Matteo Scandolo657d1322016-02-16 17:43:00 -0800394 return baseData;
395 };
396
397 const getBySubscriber = (subscriber) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800398 var deferred = $q.defer();
399 var services, tenants;
400 Services.query().$promise
401 .then((res) => {
402 services = res;
403 return Tenant.query().$promise;
404 })
405 .then((res) => {
406 tenants = res;
Matteo Scandolo657d1322016-02-16 17:43:00 -0800407 deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
Matteo Scandolo85aad312016-01-21 14:23:28 -0800408 })
409 .catch((e) => {
410 throw new Error(e);
411 });
412
413 return deferred.promise;
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800414 };
Matteo Scandolo89276392016-01-22 16:36:34 -0800415
Matteo Scandolo657d1322016-02-16 17:43:00 -0800416 const get = () => {
417 var deferred = $q.defer();
418 var services, tenants;
419 Services.query().$promise
420 .then((res) => {
421 services = res;
422 return Tenant.query({kind: 'coarse'}).$promise;
423 })
424 .then((res) => {
425 tenants = res;
426 deferred.resolve(buildServiceTree(services, tenants));
427 })
428 .catch((e) => {
429 throw new Error(e);
430 });
431
432 return deferred.promise;
433 }
434
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800435 // export APIs
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800436 return {
437 get: get,
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800438 buildServiceTree: buildServiceTree,
Matteo Scandolo657d1322016-02-16 17:43:00 -0800439 getBySubscriber: getBySubscriber,
440 buildLevel: buildLevel,
441 buildSubscriberServiceTree: buildSubscriberServiceTree,
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800442 findLevelRelation: findLevelRelation,
443 findLevelServices: findLevelServices,
444 depthOf: depthOf,
Matteo Scandolo998e4652016-01-28 12:02:57 -0800445 findSpecificInformation: findSpecificInformation
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800446 }
Matteo Scandolobe9b13d2016-01-21 11:21:03 -0800447 });
448
449}());