blob: 6e3771a6e34725fa03eba905e7546f80fb2b84cc [file] [log] [blame]
Matteo Scandolo8a64fa42016-01-21 11:21:03 -08001(function () {
2 'use strict';
3
4 angular.module('xos.serviceTopology')
5 .service('Services', function($resource){
Matteo Scandolof16b3792016-01-21 14:23:28 -08006 return $resource('/xos/services/:id', {id: '@id'});
7 })
8 .service('Tenant', function($resource){
9 return $resource('/xos/tenants');
10 })
Matteo Scandolo06f45d62016-01-21 15:38:06 -080011 .service('Slice', function($resource){
12 return $resource('/xos/slices', {id: '@id'});
13 })
14 .service('Instances', function($resource){
Matteo Scandolo170d3be2016-02-11 08:58:04 -080015 return $resource('/xos/instances', {id: '@id'}, {});
16 })
17 .service('Node', function($resource, $q, Instances){
18 return $resource('/xos/nodes', {id: '@id'}, {
19 queryWithInstances: {
20 method: 'GET',
21 isArray: true,
22 interceptor: {
23 response: function(res){
24
25 // TODO update the API to include instances in nodes
26 // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
27
28 const deferred = $q.defer();
29
30 let requests = [];
31
32 angular.forEach(res.data, (node) => {
33 requests.push(Instances.query({node: node.id}).$promise);
34 })
35
36 $q.all(requests)
37 .then((list) => {
38 res.data.map((node, i) => {
39 node.instances = list[i];
40 return node;
41 });
Matteo Scandolo170d3be2016-02-11 08:58:04 -080042 deferred.resolve(res.data);
43 })
44
45 return deferred.promise;
46 }
47 }
48 }
49 });
Matteo Scandolo06f45d62016-01-21 15:38:06 -080050 })
Matteo Scandolo7547f042016-02-09 09:13:30 -080051 .service('Subscribers', function($resource, $q, SubscriberDevice){
52 return $resource('/xos/subscribers', {id: '@id'}, {
53 queryWithDevices: {
54 method: 'GET',
55 isArray: true,
56 interceptor: {
57 response: function(res){
Matteo Scandolo219b1a72016-02-09 11:19:22 -080058
59 /**
60 * For each subscriber retrieve devices and append them
61 */
62
Matteo Scandolo7547f042016-02-09 09:13:30 -080063 const deferred = $q.defer();
64
65 let requests = [];
66
67 angular.forEach(res.data, (subscriber) => {
Matteo Scandolo219b1a72016-02-09 11:19:22 -080068 requests.push(SubscriberDevice.query({id: subscriber.id}).$promise);
Matteo Scandolo7547f042016-02-09 09:13:30 -080069 })
70
71 $q.all(requests)
72 .then((list) => {
Matteo Scandolo7e67a9a2016-02-16 16:33:26 -080073
74 // adding devices
75
Matteo Scandolo7547f042016-02-09 09:13:30 -080076 res.data.map((subscriber, i) => {
77 subscriber.devices = list[i];
Matteo Scandolo9fe01af2016-02-09 16:01:49 -080078 subscriber.type = 'subscriber';
79
80 subscriber.devices.map(d => d.type = 'device')
81
Matteo Scandolo7547f042016-02-09 09:13:30 -080082 return subscriber;
83 });
Matteo Scandolo219b1a72016-02-09 11:19:22 -080084
Matteo Scandolo9fe01af2016-02-09 16:01:49 -080085 // faking to have 2 subscriber
Matteo Scandolofd468582016-02-16 16:03:43 -080086 // res.data.push(angular.copy(res.data[0]));
Matteo Scandolo9fe01af2016-02-09 16:01:49 -080087
Matteo Scandolo7547f042016-02-09 09:13:30 -080088 deferred.resolve(res.data);
89 })
90
91 return deferred.promise;
92 }
93 }
94 }
95 });
96 })
97 .service('SubscriberDevice', function($resource){
98 return $resource('/xoslib/rs/subscriber/:id/users/', {id: '@id'});
Matteo Scandoloff7df762016-01-22 16:36:34 -080099 })
Matteo Scandolo071ef462016-01-25 12:00:42 -0800100 .service('ServiceRelation', function($q, lodash, Services, Tenant, Slice, Instances){
Matteo Scandolof16b3792016-01-21 14:23:28 -0800101
Matteo Scandolof2c99012016-01-25 10:10:38 -0800102 // count the mas depth of an object
103 const depthOf = (obj) => {
104 var depth = 0;
105 if (obj.children) {
106 obj.children.forEach(function (d) {
107 var tmpDepth = depthOf(d);
108 if (tmpDepth > depth) {
109 depth = tmpDepth
110 }
111 })
112 }
113 return 1 + depth
114 };
115
Matteo Scandolof16b3792016-01-21 14:23:28 -0800116 // find all the relation defined for a given root
117 const findLevelRelation = (tenants, rootId) => {
118 return lodash.filter(tenants, service => {
119 return service.subscriber_service === rootId;
120 });
121 };
122
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800123 const findSpecificInformation = (tenants, rootId) => {
124 var tenants = lodash.filter(tenants, service => {
125 return service.provider_service === rootId && service.subscriber_tenant;
126 });
127
128 var info;
129
130 tenants.forEach((tenant) => {
131 if(tenant.service_specific_attribute){
132 info = JSON.parse(tenant.service_specific_attribute);
133 }
134 });
135
136 return info;
137 };
138
Matteo Scandolof16b3792016-01-21 14:23:28 -0800139 // find all the service defined by a given array of relations
140 const findLevelServices = (relations, services) => {
141 const levelServices = [];
142 lodash.forEach(relations, (tenant) => {
143 var service = lodash.find(services, {id: tenant.provider_service});
144 levelServices.push(service);
145 });
146 return levelServices;
147 };
148
149 const buildLevel = (tenants, services, rootService, parentName = null) => {
150
Matteo Scandolof16b3792016-01-21 14:23:28 -0800151 // build an array of unlinked services
152 // these are the services that should still placed in the tree
153 var unlinkedServices = lodash.difference(services, [rootService]);
154
155 // find all relations relative to this rootElement
156 const levelRelation = findLevelRelation(tenants, rootService.id);
157
158 // find all items related to rootElement
159 const levelServices = findLevelServices(levelRelation, services);
160
161 // remove this item from the list (performance
162 unlinkedServices = lodash.difference(unlinkedServices, levelServices);
163
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800164 rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
165
166 const tree = {
167 name: rootService.humanReadableName,
168 parent: parentName,
169 type: 'service',
170 service: rootService,
171 children: []
172 };
173
Matteo Scandolof16b3792016-01-21 14:23:28 -0800174 lodash.forEach(levelServices, (service) => {
175 tree.children.push(buildLevel(tenants, unlinkedServices, service, rootService.humanReadableName));
176 });
177
Matteo Scandolof2c99012016-01-25 10:10:38 -0800178 // if it is the last element append internet
179 if(tree.children.length === 0){
180 tree.children.push({
Matteo Scandolo9fe01af2016-02-09 16:01:49 -0800181 name: 'Router',
182 type: 'router',
Matteo Scandolof2c99012016-01-25 10:10:38 -0800183 children: []
184 });
185 }
186
Matteo Scandolof16b3792016-01-21 14:23:28 -0800187 return tree;
188 };
189
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800190 const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800191
192 // find the root service
193 // it is the one attached to subsriber_root
194 // as now we have only one root so this can work
Matteo Scandoloff7df762016-01-22 16:36:34 -0800195 const rootServiceId = lodash.find(tenants, {subscriber_root: subscriber.id}).provider_service;
Matteo Scandolof16b3792016-01-21 14:23:28 -0800196 const rootService = lodash.find(services, {id: rootServiceId});
197
198 const serviceTree = buildLevel(tenants, services, rootService);
199
Matteo Scandoloff7df762016-01-22 16:36:34 -0800200 return {
201 name: subscriber.name,
202 parent: null,
Matteo Scandolof2c99012016-01-25 10:10:38 -0800203 type: 'subscriber',
Matteo Scandoloff7df762016-01-22 16:36:34 -0800204 children: [serviceTree]
205 };
206
Matteo Scandolof16b3792016-01-21 14:23:28 -0800207 };
208
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800209 // applying domain knowledge to build the global service tree
210 const buildServiceTree = (services, tenants) => {
211
212 // TODO refactor
213 const buildChild = (services, tenants, currentService) => {
214 let tenant = lodash.find(tenants, {subscriber_service: currentService.id});
215 if(tenant){
216 let next = lodash.find(services, {id: tenant.provider_service});
217 currentService.children = [buildChild(services, tenants, next)];
218 }
219 else {
220 currentService.children = [
221 {
222 name: 'Router',
223 type: 'router',
224 children: []
225 }
226 ]
227 }
228 currentService.type = 'service';
229 delete currentService.id; // conflict with d3
230 return currentService;
231 }
232 let baseService = lodash.find(services, {id: 3});
233
234 const baseData = {
235 name: 'Subscriber',
236 type: 'subscriber',
237 parent: null,
238 children: [buildChild(services, tenants, baseService)]
239 };
240
241 console.log(baseData);
242 return baseData;
243 };
244
245 const getBySubscriber = (subscriber) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800246 var deferred = $q.defer();
247 var services, tenants;
248 Services.query().$promise
249 .then((res) => {
250 services = res;
251 return Tenant.query().$promise;
252 })
253 .then((res) => {
254 tenants = res;
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800255 deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
Matteo Scandolof16b3792016-01-21 14:23:28 -0800256 })
257 .catch((e) => {
258 throw new Error(e);
259 });
260
261 return deferred.promise;
Matteo Scandolof2c99012016-01-25 10:10:38 -0800262 };
Matteo Scandoloff7df762016-01-22 16:36:34 -0800263
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800264 const get = () => {
265 var deferred = $q.defer();
266 var services, tenants;
267 Services.query().$promise
268 .then((res) => {
269 services = res;
270 return Tenant.query({kind: 'coarse'}).$promise;
271 })
272 .then((res) => {
273 tenants = res;
274 deferred.resolve(buildServiceTree(services, tenants));
275 })
276 .catch((e) => {
277 throw new Error(e);
278 });
279
280 return deferred.promise;
281 }
282
Matteo Scandolof2c99012016-01-25 10:10:38 -0800283 // export APIs
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800284 return {
285 get: get,
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800286 buildServiceTree: buildServiceTree,
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800287 getBySubscriber: getBySubscriber,
288 buildLevel: buildLevel,
289 buildSubscriberServiceTree: buildSubscriberServiceTree,
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800290 findLevelRelation: findLevelRelation,
291 findLevelServices: findLevelServices,
292 depthOf: depthOf,
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800293 findSpecificInformation: findSpecificInformation
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800294 }
Matteo Scandolo8a64fa42016-01-21 11:21:03 -0800295 });
296
297}());