blob: 733a690cf118f6928337da5a04c44d8ede1c12aa [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 }
31 }
32 });
33 })
34 .service('Ceilometer', function($http, $q, Instances) {
35
36 /**
37 * Get stats for a single instance
38 */
39 this.getInstanceStats = (instanceUuid) => {
40 let deferred = $q.defer();
41
42 $http.get('/xoslib/meterstatistics', {resource: instanceUuid})
43 .then((res) => {
44 deferred.resolve(res.data);
45 })
46 .catch((e) => {
47 deferred.reject(e);
48 })
49
50 return deferred.promise;
51 };
52
53 /**
54 * Collect stats for an array of instances
55 */
56 this.getInstancesStats = (instances) => {
57 let deferred = $q.defer();
58 let instancePromises = [];
59 let instanceList = [];
60
61 // retrieve instance details
62 instances.forEach((instanceId) => {
63 instancePromises.push(Instances.get({id: instanceId}).$promise);
64 });
65
66 // get all instance data
67 $q.all(instancePromises)
68 .then((_instanceList) => {
69 instanceList = _instanceList;
70 let promises = [];
71 // foreach instance query stats
72 instanceList.forEach((instance) => {
73 promises.push(this.getInstanceStats(instance.instance_uuid));
74 });
75 return $q.all(promises);
76 })
77 .then(stats => {
78 // augment instance with stats information
79 instanceList.map((instance, i) => {
80 instance.stats = stats[i];
81 });
82 deferred.resolve(instanceList);
83 })
84 .catch(deferred.reject);
85
86 return deferred.promise;
87 };
Matteo Scandolo85aad312016-01-21 14:23:28 -080088 })
Matteo Scandolo68236262016-01-21 15:38:06 -080089 .service('Slice', function($resource){
90 return $resource('/xos/slices', {id: '@id'});
91 })
92 .service('Instances', function($resource){
Matteo Scandoloba2d63d2016-02-17 13:54:11 -080093 return $resource('/xos/instances/:id', {id: '@id'});
Matteo Scandolo14183932016-02-11 08:58:04 -080094 })
95 .service('Node', function($resource, $q, Instances){
96 return $resource('/xos/nodes', {id: '@id'}, {
97 queryWithInstances: {
98 method: 'GET',
99 isArray: true,
100 interceptor: {
101 response: function(res){
102
103 // TODO update the API to include instances in nodes
104 // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
105
106 const deferred = $q.defer();
107
108 let requests = [];
109
110 angular.forEach(res.data, (node) => {
111 requests.push(Instances.query({node: node.id}).$promise);
112 })
113
114 $q.all(requests)
115 .then((list) => {
116 res.data.map((node, i) => {
117 node.instances = list[i];
118 return node;
119 });
Matteo Scandolo14183932016-02-11 08:58:04 -0800120 deferred.resolve(res.data);
121 })
122
123 return deferred.promise;
124 }
125 }
126 }
127 });
Matteo Scandolo68236262016-01-21 15:38:06 -0800128 })
Matteo Scandolo735606c2016-02-09 09:13:30 -0800129 .service('Subscribers', function($resource, $q, SubscriberDevice){
130 return $resource('/xos/subscribers', {id: '@id'}, {
131 queryWithDevices: {
132 method: 'GET',
133 isArray: true,
134 interceptor: {
135 response: function(res){
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800136
137 /**
138 * For each subscriber retrieve devices and append them
139 */
140
Matteo Scandolo735606c2016-02-09 09:13:30 -0800141 const deferred = $q.defer();
142
143 let requests = [];
144
145 angular.forEach(res.data, (subscriber) => {
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800146 requests.push(SubscriberDevice.query({id: subscriber.id}).$promise);
Matteo Scandolo735606c2016-02-09 09:13:30 -0800147 })
148
149 $q.all(requests)
150 .then((list) => {
Matteo Scandolo4aae3aa2016-02-16 16:33:26 -0800151
152 // adding devices
153
Matteo Scandolo735606c2016-02-09 09:13:30 -0800154 res.data.map((subscriber, i) => {
155 subscriber.devices = list[i];
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800156 subscriber.type = 'subscriber';
157
158 subscriber.devices.map(d => d.type = 'device')
159
Matteo Scandolo735606c2016-02-09 09:13:30 -0800160 return subscriber;
161 });
Matteo Scandoloeeb9c082016-02-09 11:19:22 -0800162
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800163 // faking to have 2 subscriber
Matteo Scandoloc2c6fb02016-02-16 16:03:43 -0800164 // res.data.push(angular.copy(res.data[0]));
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800165
Matteo Scandolo735606c2016-02-09 09:13:30 -0800166 deferred.resolve(res.data);
167 })
168
169 return deferred.promise;
170 }
171 }
172 }
173 });
174 })
175 .service('SubscriberDevice', function($resource){
176 return $resource('/xoslib/rs/subscriber/:id/users/', {id: '@id'});
Matteo Scandolo89276392016-01-22 16:36:34 -0800177 })
Matteo Scandolo4889f5a2016-01-25 12:00:42 -0800178 .service('ServiceRelation', function($q, lodash, Services, Tenant, Slice, Instances){
Matteo Scandolo85aad312016-01-21 14:23:28 -0800179
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800180 // count the mas depth of an object
181 const depthOf = (obj) => {
182 var depth = 0;
183 if (obj.children) {
184 obj.children.forEach(function (d) {
185 var tmpDepth = depthOf(d);
186 if (tmpDepth > depth) {
187 depth = tmpDepth
188 }
189 })
190 }
191 return 1 + depth
192 };
193
Matteo Scandolo85aad312016-01-21 14:23:28 -0800194 // find all the relation defined for a given root
195 const findLevelRelation = (tenants, rootId) => {
196 return lodash.filter(tenants, service => {
197 return service.subscriber_service === rootId;
198 });
199 };
200
Matteo Scandolo998e4652016-01-28 12:02:57 -0800201 const findSpecificInformation = (tenants, rootId) => {
202 var tenants = lodash.filter(tenants, service => {
203 return service.provider_service === rootId && service.subscriber_tenant;
204 });
205
206 var info;
207
208 tenants.forEach((tenant) => {
209 if(tenant.service_specific_attribute){
210 info = JSON.parse(tenant.service_specific_attribute);
211 }
212 });
213
214 return info;
215 };
216
Matteo Scandolo85aad312016-01-21 14:23:28 -0800217 // find all the service defined by a given array of relations
218 const findLevelServices = (relations, services) => {
219 const levelServices = [];
220 lodash.forEach(relations, (tenant) => {
221 var service = lodash.find(services, {id: tenant.provider_service});
222 levelServices.push(service);
223 });
224 return levelServices;
225 };
226
227 const buildLevel = (tenants, services, rootService, parentName = null) => {
228
Matteo Scandolo85aad312016-01-21 14:23:28 -0800229 // build an array of unlinked services
230 // these are the services that should still placed in the tree
231 var unlinkedServices = lodash.difference(services, [rootService]);
232
233 // find all relations relative to this rootElement
234 const levelRelation = findLevelRelation(tenants, rootService.id);
235
236 // find all items related to rootElement
237 const levelServices = findLevelServices(levelRelation, services);
238
239 // remove this item from the list (performance
240 unlinkedServices = lodash.difference(unlinkedServices, levelServices);
241
Matteo Scandolo998e4652016-01-28 12:02:57 -0800242 rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
243
244 const tree = {
245 name: rootService.humanReadableName,
246 parent: parentName,
247 type: 'service',
248 service: rootService,
249 children: []
250 };
251
Matteo Scandolo85aad312016-01-21 14:23:28 -0800252 lodash.forEach(levelServices, (service) => {
253 tree.children.push(buildLevel(tenants, unlinkedServices, service, rootService.humanReadableName));
254 });
255
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800256 // if it is the last element append internet
257 if(tree.children.length === 0){
258 tree.children.push({
Matteo Scandolo38ba3312016-02-09 16:01:49 -0800259 name: 'Router',
260 type: 'router',
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800261 children: []
262 });
263 }
264
Matteo Scandolo85aad312016-01-21 14:23:28 -0800265 return tree;
266 };
267
Matteo Scandolo657d1322016-02-16 17:43:00 -0800268 const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800269
270 // find the root service
271 // it is the one attached to subsriber_root
272 // as now we have only one root so this can work
Matteo Scandolo89276392016-01-22 16:36:34 -0800273 const rootServiceId = lodash.find(tenants, {subscriber_root: subscriber.id}).provider_service;
Matteo Scandolo85aad312016-01-21 14:23:28 -0800274 const rootService = lodash.find(services, {id: rootServiceId});
275
276 const serviceTree = buildLevel(tenants, services, rootService);
277
Matteo Scandolo89276392016-01-22 16:36:34 -0800278 return {
279 name: subscriber.name,
280 parent: null,
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800281 type: 'subscriber',
Matteo Scandolo89276392016-01-22 16:36:34 -0800282 children: [serviceTree]
283 };
284
Matteo Scandolo85aad312016-01-21 14:23:28 -0800285 };
286
Matteo Scandolo657d1322016-02-16 17:43:00 -0800287 // applying domain knowledge to build the global service tree
288 const buildServiceTree = (services, tenants) => {
289
290 // TODO refactor
291 const buildChild = (services, tenants, currentService) => {
292 let tenant = lodash.find(tenants, {subscriber_service: currentService.id});
293 if(tenant){
294 let next = lodash.find(services, {id: tenant.provider_service});
295 currentService.children = [buildChild(services, tenants, next)];
296 }
297 else {
298 currentService.children = [
299 {
300 name: 'Router',
301 type: 'router',
302 children: []
303 }
304 ]
305 }
306 currentService.type = 'service';
307 delete currentService.id; // conflict with d3
308 return currentService;
309 }
310 let baseService = lodash.find(services, {id: 3});
311
312 const baseData = {
313 name: 'Subscriber',
314 type: 'subscriber',
315 parent: null,
316 children: [buildChild(services, tenants, baseService)]
317 };
Matteo Scandolo657d1322016-02-16 17:43:00 -0800318 return baseData;
319 };
320
321 const getBySubscriber = (subscriber) => {
Matteo Scandolo85aad312016-01-21 14:23:28 -0800322 var deferred = $q.defer();
323 var services, tenants;
324 Services.query().$promise
325 .then((res) => {
326 services = res;
327 return Tenant.query().$promise;
328 })
329 .then((res) => {
330 tenants = res;
Matteo Scandolo657d1322016-02-16 17:43:00 -0800331 deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
Matteo Scandolo85aad312016-01-21 14:23:28 -0800332 })
333 .catch((e) => {
334 throw new Error(e);
335 });
336
337 return deferred.promise;
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800338 };
Matteo Scandolo89276392016-01-22 16:36:34 -0800339
Matteo Scandolo657d1322016-02-16 17:43:00 -0800340 const get = () => {
341 var deferred = $q.defer();
342 var services, tenants;
343 Services.query().$promise
344 .then((res) => {
345 services = res;
346 return Tenant.query({kind: 'coarse'}).$promise;
347 })
348 .then((res) => {
349 tenants = res;
350 deferred.resolve(buildServiceTree(services, tenants));
351 })
352 .catch((e) => {
353 throw new Error(e);
354 });
355
356 return deferred.promise;
357 }
358
Matteo Scandolofb46f5b2016-01-25 10:10:38 -0800359 // export APIs
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800360 return {
361 get: get,
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800362 buildServiceTree: buildServiceTree,
Matteo Scandolo657d1322016-02-16 17:43:00 -0800363 getBySubscriber: getBySubscriber,
364 buildLevel: buildLevel,
365 buildSubscriberServiceTree: buildSubscriberServiceTree,
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800366 findLevelRelation: findLevelRelation,
367 findLevelServices: findLevelServices,
368 depthOf: depthOf,
Matteo Scandolo998e4652016-01-28 12:02:57 -0800369 findSpecificInformation: findSpecificInformation
Matteo Scandoloc86b4c12016-01-25 17:36:08 -0800370 }
Matteo Scandolobe9b13d2016-01-21 11:21:03 -0800371 });
372
373}());