blob: d5e924ff674345043f9ad8b1b62d45e5fb684e37 [file] [log] [blame]
Matteo Scandolobe9b13d2016-01-21 11:21:03 -08001(function () {
2 'use strict';
3
4 angular.module('xos.serviceTopology')
5 .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 Scandoloc303fd02016-02-17 15:11:33 -080052 $http.get('/xoslib/meterstatistics', {params:{resource: 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 Scandolo85aad312016-01-21 14:23:28 -080098 })
Matteo Scandolo68236262016-01-21 15:38:06 -080099 .service('Slice', function($resource){
100 return $resource('/xos/slices', {id: '@id'});
101 })
102 .service('Instances', function($resource){
Matteo Scandoloba2d63d2016-02-17 13:54:11 -0800103 return $resource('/xos/instances/:id', {id: '@id'});
Matteo Scandolo14183932016-02-11 08:58:04 -0800104 })
105 .service('Node', function($resource, $q, Instances){
106 return $resource('/xos/nodes', {id: '@id'}, {
107 queryWithInstances: {
108 method: 'GET',
109 isArray: true,
110 interceptor: {
111 response: function(res){
112
113 // TODO update the API to include instances in nodes
114 // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
115
116 const deferred = $q.defer();
117
118 let requests = [];
119
120 angular.forEach(res.data, (node) => {
121 requests.push(Instances.query({node: node.id}).$promise);
122 })
123
124 $q.all(requests)
125 .then((list) => {
126 res.data.map((node, i) => {
127 node.instances = list[i];
128 return node;
129 });
Matteo Scandolo14183932016-02-11 08:58:04 -0800130 deferred.resolve(res.data);
131 })
132
133 return deferred.promise;
134 }
135 }
136 }
137 });
Matteo Scandolo68236262016-01-21 15:38:06 -0800138 })
Matteo Scandolo735606c2016-02-09 09:13:30 -0800139 .service('Subscribers', function($resource, $q, SubscriberDevice){
Matteo Scandolodffc1382016-02-22 14:53:44 -0800140 return $resource('/xos/subscribers/:id', {id: '@id'}, {
Matteo Scandolo735606c2016-02-09 09:13:30 -0800141 queryWithDevices: {
142 method: 'GET',
143 isArray: true,
144 interceptor: {
145 response: function(res){
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800146
147 /**
148 * For each subscriber retrieve devices and append them
149 */
150
Matteo Scandolodffc1382016-02-22 14:53:44 -0800151 let deferred = $q.defer();
Matteo Scandolo735606c2016-02-09 09:13:30 -0800152
153 let requests = [];
154
155 angular.forEach(res.data, (subscriber) => {
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800156 requests.push(SubscriberDevice.query({id: subscriber.id}).$promise);
Matteo Scandolo735606c2016-02-09 09:13:30 -0800157 })
158
159 $q.all(requests)
160 .then((list) => {
Matteo Scandolo4aae3aa2016-02-16 16:33:26 -0800161
162 // adding devices
163
Matteo Scandolo735606c2016-02-09 09:13:30 -0800164 res.data.map((subscriber, i) => {
165 subscriber.devices = list[i];
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800166 subscriber.type = 'subscriber';
167
168 subscriber.devices.map(d => d.type = 'device')
169
Matteo Scandolo735606c2016-02-09 09:13:30 -0800170 return subscriber;
171 });
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800172
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800173 // faking to have 2 subscriber
Matteo Scandoloc2c6fb02016-02-16 16:03:43 -0800174 // res.data.push(angular.copy(res.data[0]));
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800175
Matteo Scandolo735606c2016-02-09 09:13:30 -0800176 deferred.resolve(res.data);
177 })
178
179 return deferred.promise;
180 }
181 }
Matteo Scandolodffc1382016-02-22 14:53:44 -0800182 },
183 getWithDevices: {
184 method: 'GET',
185 isArray: false,
186 interceptor: {
187 response: (res) => {
188 let d = $q.defer();
189
190 SubscriberDevice.query({id: res.data.id}).$promise
191 .then(devices => {
192 devices.map(d => d.type = 'device');
193 res.data.devices = devices;
194 res.data.type = 'subscriber';
Matteo Scandolodffc1382016-02-22 14:53:44 -0800195 d.resolve(res.data);
196 })
197 .catch(err => {
198 d.reject(err);
199 });
200
201 return d.promise;
202 }
203 }
Matteo Scandolo735606c2016-02-09 09:13:30 -0800204 }
205 });
206 })
207 .service('SubscriberDevice', function($resource){
208 return $resource('/xoslib/rs/subscriber/:id/users/', {id: '@id'});
Matteo Scandolo89276392016-01-22 16:36:34 -0800209 })
Matteo Scandolo4889f5a2016-01-25 12:00:42 -0800210 .service('ServiceRelation', function($q, lodash, Services, Tenant, Slice, Instances){
Matteo Scandolo85aad312016-01-21 14:23:28 -0800211
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800212 // count the mas depth of an object
213 const depthOf = (obj) => {
214 var depth = 0;
215 if (obj.children) {
216 obj.children.forEach(function (d) {
217 var tmpDepth = depthOf(d);
218 if (tmpDepth > depth) {
219 depth = tmpDepth
220 }
221 })
222 }
223 return 1 + depth
224 };
225
Matteo Scandolo85aad312016-01-21 14:23:28 -0800226 // find all the relation defined for a given root
227 const findLevelRelation = (tenants, rootId) => {
228 return lodash.filter(tenants, service => {
229 return service.subscriber_service === rootId;
230 });
231 };
232
Matteo Scandolo998e4652016-01-28 12:02:57 -0800233 const findSpecificInformation = (tenants, rootId) => {
234 var tenants = lodash.filter(tenants, service => {
235 return service.provider_service === rootId && service.subscriber_tenant;
236 });
237
238 var info;
239
240 tenants.forEach((tenant) => {
241 if(tenant.service_specific_attribute){
242 info = JSON.parse(tenant.service_specific_attribute);
243 }
244 });
245
246 return info;
247 };
248
Matteo Scandolo85aad312016-01-21 14:23:28 -0800249 // find all the service defined by a given array of relations
250 const findLevelServices = (relations, services) => {
251 const levelServices = [];
252 lodash.forEach(relations, (tenant) => {
253 var service = lodash.find(services, {id: tenant.provider_service});
254 levelServices.push(service);
255 });
256 return levelServices;
257 };
258
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800259 const buildLevel = (tenants, services, rootService, rootTenant, parentName = null) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800260
Matteo Scandolo85aad312016-01-21 14:23:28 -0800261 // build an array of unlinked services
262 // these are the services that should still placed in the tree
263 var unlinkedServices = lodash.difference(services, [rootService]);
264
265 // find all relations relative to this rootElement
266 const levelRelation = findLevelRelation(tenants, rootService.id);
Matteo Scandolo85aad312016-01-21 14:23:28 -0800267 // find all items related to rootElement
268 const levelServices = findLevelServices(levelRelation, services);
269
270 // remove this item from the list (performance
271 unlinkedServices = lodash.difference(unlinkedServices, levelServices);
272
Matteo Scandolo998e4652016-01-28 12:02:57 -0800273 rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
274
275 const tree = {
276 name: rootService.humanReadableName,
277 parent: parentName,
278 type: 'service',
279 service: rootService,
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800280 tenant: rootTenant,
Matteo Scandolo998e4652016-01-28 12:02:57 -0800281 children: []
282 };
283
Matteo Scandolo85aad312016-01-21 14:23:28 -0800284 lodash.forEach(levelServices, (service) => {
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800285 let tenant = lodash.find(tenants, {subscriber_tenant: rootTenant.id, provider_service: service.id});
286 tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
Matteo Scandolo85aad312016-01-21 14:23:28 -0800287 });
288
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800289 // if it is the last element append internet
290 if(tree.children.length === 0){
291 tree.children.push({
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800292 name: 'Router',
293 type: 'router',
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800294 children: []
295 });
296 }
297
Matteo Scandolo85aad312016-01-21 14:23:28 -0800298 return tree;
299 };
300
Matteo Scandolo657d1322016-02-16 17:43:00 -0800301 const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800302
303 // find the root service
304 // it is the one attached to subsriber_root
305 // as now we have only one root so this can work
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800306 const rootTenant = lodash.find(tenants, {subscriber_root: subscriber.id});
307 const rootService = lodash.find(services, {id: rootTenant.provider_service});
Matteo Scandolo85aad312016-01-21 14:23:28 -0800308
Matteo Scandolo0344ef32016-02-22 16:53:22 -0800309 const serviceTree = buildLevel(tenants, services, rootService, rootTenant);
Matteo Scandolo85aad312016-01-21 14:23:28 -0800310
Matteo Scandolo89276392016-01-22 16:36:34 -0800311 return {
312 name: subscriber.name,
313 parent: null,
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800314 type: 'subscriber',
Matteo Scandolo89276392016-01-22 16:36:34 -0800315 children: [serviceTree]
316 };
317
Matteo Scandolo85aad312016-01-21 14:23:28 -0800318 };
319
Matteo Scandolo657d1322016-02-16 17:43:00 -0800320 // applying domain knowledge to build the global service tree
321 const buildServiceTree = (services, tenants) => {
322
323 // TODO refactor
324 const buildChild = (services, tenants, currentService) => {
Matteo Scandolodffc1382016-02-22 14:53:44 -0800325
326 const response = {
327 type: 'service',
328 name: currentService.humanReadableName,
329 service: currentService
330 };
331
Matteo Scandolo657d1322016-02-16 17:43:00 -0800332 let tenant = lodash.find(tenants, {subscriber_service: currentService.id});
333 if(tenant){
334 let next = lodash.find(services, {id: tenant.provider_service});
Matteo Scandolodffc1382016-02-22 14:53:44 -0800335 response.children = [buildChild(services, tenants, next)];
Matteo Scandolo657d1322016-02-16 17:43:00 -0800336 }
337 else {
Matteo Scandolodffc1382016-02-22 14:53:44 -0800338 response.children = [
Matteo Scandolo657d1322016-02-16 17:43:00 -0800339 {
340 name: 'Router',
341 type: 'router',
342 children: []
343 }
344 ]
345 }
Matteo Scandolo657d1322016-02-16 17:43:00 -0800346 delete currentService.id; // conflict with d3
Matteo Scandolodffc1382016-02-22 14:53:44 -0800347 return response;
Matteo Scandolo657d1322016-02-16 17:43:00 -0800348 }
349 let baseService = lodash.find(services, {id: 3});
350
351 const baseData = {
352 name: 'Subscriber',
353 type: 'subscriber',
354 parent: null,
355 children: [buildChild(services, tenants, baseService)]
356 };
Matteo Scandolo657d1322016-02-16 17:43:00 -0800357 return baseData;
358 };
359
360 const getBySubscriber = (subscriber) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800361 var deferred = $q.defer();
362 var services, tenants;
363 Services.query().$promise
364 .then((res) => {
365 services = res;
366 return Tenant.query().$promise;
367 })
368 .then((res) => {
369 tenants = res;
Matteo Scandolo657d1322016-02-16 17:43:00 -0800370 deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
Matteo Scandolo85aad312016-01-21 14:23:28 -0800371 })
372 .catch((e) => {
373 throw new Error(e);
374 });
375
376 return deferred.promise;
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800377 };
Matteo Scandolo89276392016-01-22 16:36:34 -0800378
Matteo Scandolo657d1322016-02-16 17:43:00 -0800379 const get = () => {
380 var deferred = $q.defer();
381 var services, tenants;
382 Services.query().$promise
383 .then((res) => {
384 services = res;
385 return Tenant.query({kind: 'coarse'}).$promise;
386 })
387 .then((res) => {
388 tenants = res;
389 deferred.resolve(buildServiceTree(services, tenants));
390 })
391 .catch((e) => {
392 throw new Error(e);
393 });
394
395 return deferred.promise;
396 }
397
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800398 // export APIs
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800399 return {
400 get: get,
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800401 buildServiceTree: buildServiceTree,
Matteo Scandolo657d1322016-02-16 17:43:00 -0800402 getBySubscriber: getBySubscriber,
403 buildLevel: buildLevel,
404 buildSubscriberServiceTree: buildSubscriberServiceTree,
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800405 findLevelRelation: findLevelRelation,
406 findLevelServices: findLevelServices,
407 depthOf: depthOf,
Matteo Scandolo998e4652016-01-28 12:02:57 -0800408 findSpecificInformation: findSpecificInformation
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800409 }
Matteo Scandolobe9b13d2016-01-21 11:21:03 -0800410 });
411
412}());